Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this valid C++ code?

58 views
Skip to first unread message

daniel...@gmail.com

unread,
Oct 3, 2022, 5:10:06 PM10/3/22
to
Hello everyone,

Is the C++ code below valid?

#include <iostream>
#include <string_view>
#include <string>

template <class T, class Enable = void>
class Foo
{};

template <class T>
class Foo<T,typename std::enable_if<std::is_same<T,std::string>::value>::type>
{
public:

void f(std::string s)
{
Foo<std::string_view> foo; // (*)
foo.f(s);
}
};

template <class T>
class Foo<T, typename std::enable_if<std::is_same<T, std::string_view>::value>::type>
{
public:

void f(std::string_view s)
{
std::cout << s << "\n";
}
};

int main()
{
Foo<std::string> foo;
foo.f("Hello World");
}

LLVM (clang-cl) says "yes", and outputs "Hello World".

Visual Studio 2022 (v143) says "no", "'f': is not a member of 'Foo<std::basic_string_view<char,std::char_traits<char>>,void>", 17
at line (*)

Both compiled with C++17.

Thanks,
Daniel

David LaRue

unread,
Oct 3, 2022, 7:53:04 PM10/3/22
to
"daniel...@gmail.com" <daniel...@gmail.com> wrote in
news:bc46c146-abb5-4b16...@googlegroups.com:

> Hello everyone,
>
> Is the C++ code below valid?

When asking such a question, you should specify the standard or compilers
that you are interested in using. As you see from the results below, one
compiler says it isn't valid and the other says it is valid. The
difference is likely in the standard that each implements as its
standard. Note that the applicable standard may be controlled by a
setting.

daniel...@gmail.com

unread,
Oct 3, 2022, 9:07:10 PM10/3/22
to
On Monday, October 3, 2022 at 7:53:04 PM UTC-4, David LaRue wrote:
> "daniel...@gmail.com" <daniel...@gmail.com> wrote in
> news:bc46c146-abb5-4b16...@googlegroups.com:
> > Hello everyone,
> >
> > Is the C++ code below valid?
> When asking such a question, you should specify the standard or compilers
> that you are interested in using. As you see from the results below, one
> compiler says it isn't valid and the other says it is valid. The
> difference is likely in the standard that each implements as its
> standard. Note that the applicable standard may be controlled by a
> setting.

I'm interested in responses about whether the posted code is valid
C++ code or not for standards C++ 11 or greater. I'm not interested
in whether it "works" for one compiler or another, only whether it's
valid C++ code according to the standard.

Thanks,
Daniel


daniel...@gmail.com

unread,
Oct 3, 2022, 9:42:34 PM10/3/22
to
On Monday, October 3, 2022 at 9:07:10 PM UTC-4, daniel...@gmail.com wrote:

> I'm interested in responses about whether the posted code is valid
> C++ code or not for standards C++ 11 or greater. I'm not interested
> in whether it "works" for one compiler or another, only whether it's
> valid C++ code according to the standard.
>
Or rather, since I used std:string_view in the example code, for C++ 17
or later :-)

Juha Nieminen

unread,
Oct 4, 2022, 2:06:01 AM10/4/22
to
David LaRue <huey...@tampabay.rr.com> wrote:
> When asking such a question, you should specify the standard or compilers
> that you are interested in using.

But he did:

>> Both compiled with C++17.

Bo Persson

unread,
Oct 4, 2022, 7:48:09 AM10/4/22
to
Seems like g++ (v12.2) agrees with VC++, and also points out the problem
that the specialization is defined after its first use.

My (non-language-lawyer) interpretation is that since f and its local
foo don't depend on the template parameter T, they should be looked up
immediately, and not at the point of instantiation.


daniel...@gmail.com

unread,
Oct 4, 2022, 8:22:22 AM10/4/22
to
Thanks!
Daniel

Manfred

unread,
Oct 4, 2022, 8:54:44 PM10/4/22
to
A good example of when someone's question, and its answer, are useful
for someone else too.
Thanks.


Andrey Tarasevich

unread,
Oct 7, 2022, 3:41:57 PM10/7/22
to
Your program is invalid (ill-formed). However, no diagnostic is required.

An issue of the same general nature can be demonstrated by a more simple
example

class C;

template <typename T = int> void foo() {
C c; // Incomplete type error? Or not?
}

int main() {
foo();
}

class C {};

Note that the above code is also quietly accepted by GCC, but rejected
by MSVC and Clang.

Briefly and informally, the rule it violates says the following: if the
interpretation of your template changes depending on its point of
instantiation, the program is ill-formed. In a more focused and formal
form: if a reference to an non-dependent name from an imaginary
instantiation that immediately follows the definition is invalid, the
program is ill-formed.

A complete set of formal requirements can be found in [temp.res]:

https://timsong-cpp.github.io/cppwp/n4659/temp.res#8.3
https://timsong-cpp.github.io/cppwp/n4659/temp.res#8.4
https://timsong-cpp.github.io/cppwp/n4659/temp.res#temp.point-8

The first two links deal with non-dependent names, while the third one
applies to dependent names. But the general idea is the same: if the
meaning of a template specialization depends on its point of
instantiation, the program is ill-formed. If the meaning of a template
specialization changes as you move it up and down in the translation
unit, the program is ill-formed. Yet, no diagnostic is required.

This is basically it.

But there's another detail at play here. The freedom provided by "no
diagnostic is required" supplies the implementations with quite a bit of
leeway in choosing the point of instantiation. The obvious next logical
step is the resolution of DR#993

https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#993

It allows implementations to stop worrying about choosing the proper
point of instantiation completely. It allows them to simply push all
instantiations to the very end of the translation unit and be done with it.

This is an opportunity GCC immediately took advantage of. GCC
instantiates templates at the very end of the TU and, expectedly,
interprets their content from that vantage point. Which is why GCC
reports errors neither in your example nor in mine. Meanwhile, Clang and
MSVC still stick to the "early instantiation" approach, which allows
them to see the problems in our examples.

--
Best regards,
Andrey

Andrey Tarasevich

unread,
Oct 8, 2022, 2:18:38 PM10/8/22
to
On 10/7/2022 12:41 PM, Andrey Tarasevich wrote:
>
> This is an opportunity GCC immediately took advantage of. GCC
> instantiates templates at the very end of the TU and, expectedly,
> interprets their content from that vantage point. Which is why GCC
> reports errors neither in your example nor in mine. Meanwhile, Clang and
> MSVC still stick to the "early instantiation" approach, which allows
> them to see the problems in our examples.
>

Oh, I see that it was actually Clang that accepted the code...

Frankly, I'm having hard time trying to find a single version of Clang
that would accept it. GCC complains too, since partial specialization
after instantiation is a different kind of error. And a well-diagnosable
one.

Which version of Clang were you using?

--
Best regards,
Andrey


0 new messages