Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #86787 > unrolled thread

Is this valid C++ code?

Started by"daniel...@gmail.com" <danielaparker@gmail.com>
First post2022-10-03 14:09 -0700
Last post2022-10-08 11:18 -0700
Articles 10 — 6 participants

Back to article view | Back to comp.lang.c++


Contents

  Is this valid C++ code? "daniel...@gmail.com" <danielaparker@gmail.com> - 2022-10-03 14:09 -0700
    Re: Is this valid C++ code? David LaRue <huey.dll@tampabay.rr.com> - 2022-10-03 23:52 +0000
      Re: Is this valid C++ code? "daniel...@gmail.com" <danielaparker@gmail.com> - 2022-10-03 18:07 -0700
        Re: Is this valid C++ code? "daniel...@gmail.com" <danielaparker@gmail.com> - 2022-10-03 18:42 -0700
      Re: Is this valid C++ code? Juha Nieminen <nospam@thanks.invalid> - 2022-10-04 06:05 +0000
    Re: Is this valid C++ code? Bo Persson <bo@bo-persson.se> - 2022-10-04 13:47 +0200
      Re: Is this valid C++ code? "daniel...@gmail.com" <danielaparker@gmail.com> - 2022-10-04 05:22 -0700
      Re: Is this valid C++ code? Manfred <noname@add.invalid> - 2022-10-05 02:54 +0200
    Re: Is this valid C++ code? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-10-07 12:41 -0700
      Re: Is this valid C++ code? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-10-08 11:18 -0700

#86787 — Is this valid C++ code?

From"daniel...@gmail.com" <danielaparker@gmail.com>
Date2022-10-03 14:09 -0700
SubjectIs this valid C++ code?
Message-ID<bc46c146-abb5-4b16-b62d-324e049c7083n@googlegroups.com>
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

[toc] | [next] | [standalone]


#86788

FromDavid LaRue <huey.dll@tampabay.rr.com>
Date2022-10-03 23:52 +0000
Message-ID<XnsAF25CA3284913hueydlltampabayrrcom@46.165.242.75>
In reply to#86787
"daniel...@gmail.com" <danielaparker@gmail.com> wrote in
news:bc46c146-abb5-4b16-b62d-324e049c7083n@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.
 
> #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
> 

[toc] | [prev] | [next] | [standalone]


#86789

From"daniel...@gmail.com" <danielaparker@gmail.com>
Date2022-10-03 18:07 -0700
Message-ID<fb857369-f722-4c85-b185-d576a4b7c32fn@googlegroups.com>
In reply to#86788
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

  

[toc] | [prev] | [next] | [standalone]


#86790

From"daniel...@gmail.com" <danielaparker@gmail.com>
Date2022-10-03 18:42 -0700
Message-ID<e3c311c4-f2f1-4cb4-8ee2-07526ce3a870n@googlegroups.com>
In reply to#86789
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 :-)

[toc] | [prev] | [next] | [standalone]


#86792

FromJuha Nieminen <nospam@thanks.invalid>
Date2022-10-04 06:05 +0000
Message-ID<thgifm$174c$2@gioia.aioe.org>
In reply to#86788
David LaRue <huey.dll@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.

[toc] | [prev] | [next] | [standalone]


#86793

FromBo Persson <bo@bo-persson.se>
Date2022-10-04 13:47 +0200
Message-ID<jq2kr7Ft790U1@mid.individual.net>
In reply to#86787
On 2022-10-03 at 23:09, daniel...@gmail.com wrote:
> 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.
> 

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.

[toc] | [prev] | [next] | [standalone]


#86794

From"daniel...@gmail.com" <danielaparker@gmail.com>
Date2022-10-04 05:22 -0700
Message-ID<40c751c7-806c-4921-a029-a355b0568671n@googlegroups.com>
In reply to#86793
On Tuesday, October 4, 2022 at 7:48:09 AM UTC-4, Bo Persson wrote:
> On 2022-10-03 at 23:09, daniel...@gmail.com wrote: 
> > 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. 
> >
> 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.

Thanks! 
Daniel

[toc] | [prev] | [next] | [standalone]


#86796

FromManfred <noname@add.invalid>
Date2022-10-05 02:54 +0200
Message-ID<thikk1$4vd$1@gioia.aioe.org>
In reply to#86793
On 10/4/2022 1:47 PM, Bo Persson wrote:
> On 2022-10-03 at 23:09, daniel...@gmail.com wrote:
>> 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.
>>
> 
> 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.
> 
> 

A good example of when someone's question, and its answer, are useful 
for someone else too.
Thanks.

[toc] | [prev] | [next] | [standalone]


#86832

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-10-07 12:41 -0700
Message-ID<thpvdl$3qfkl$2@dont-email.me>
In reply to#86787
On 10/3/2022 2:09 PM, daniel...@gmail.com wrote:
> 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.
> 

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

[toc] | [prev] | [next] | [standalone]


#86838

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2022-10-08 11:18 -0700
Message-ID<thseta$83se$1@dont-email.me>
In reply to#86832
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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web