19

I am learning C++ using the books listed here. In particular, I learnt that we cannot use std::string as a non-type template parameter. Now, to further clear my concept of the subject I tried the following example which compiles in gcc and msvc but not in clang. Demo

std::string nameOk[] = {"name1", "name2"};
template<std::string &name>
void foo()
{
   
}
int main()
{
    
    foo<nameOk[0]>(); //this compiles in gcc and msvc but not in clang in C++20  
}

My question is which compiler is right here(if any). That is, is the program well-formed or IFNDR.

Alex
  • 318
  • 1
  • 14
  • 2
    It seems odd to allow a non-`const` `std::string` to be passed as a template parameter... – ShadowRanger Sep 16 '22 at 11:16
  • 2
    @ShadowRanger We can pass a nonconst global `std::string`. See [this example](https://stackoverflow.com/a/5687575/12002570) where this is shown. – Jason Sep 16 '22 at 11:22
  • 1
    First of all note that you are not using `std::string` as the template argument, you're using `std::string&`, which is allowed. Secondly, it seems to be a bug in Clang that it doesn't allow it. – Some programmer dude Sep 16 '22 at 11:26
  • @Someprogrammerdude Yes **I already know that `std::string` is not a valid nontype template parameter as written at the beginning of my question**. Kindly read the question again. That is the reason I tried `std::string&` and was surprised that it does not compile in some compilers. Also, I'm looking for an authoritative answer. – Alex Sep 16 '22 at 11:40
  • The accepted answer in the post @JasonLiam refered to (https://stackoverflow.com/questions/5687540/non-type-template-parameters/5687575#5687575) quotes the standard regarding non-type template parameters. _"lvalue reference to object"_ is one of the options there. – wohlstad Sep 16 '22 at 11:51
  • 1
    Sounds like Clang isn't implementing the newest wording, which AFAICS permits subobjects as non-type template arguments (as opposed to C++14/17) – Columbo Sep 16 '22 at 12:00
  • @JasonLiam: Neat. Strange, but neat. :-) – ShadowRanger Sep 16 '22 at 14:43
  • Include your error message in the question! – Ben Voigt Sep 16 '22 at 20:15

2 Answers2

14

Clang is complaining that your template argument is a subobject. (If you make the argument a complete string object, it works.)

This behavior is based on an earlier restriction in the standard at [temp.arg.nontype], which read

For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • a subobject (6.7.2 [intro.object]),

This restriction is lifted as of P1907 which is in C++20, but Clang hasn't reflected that yet. GCC also fails when you use e.g. version 10 with C++17:

error: '& nameOk[0]' is not a valid template argument of type 'std::string&' {aka 'std::__cxx11::basic_string<char>&'} because 'nameOk[0]' is not a variable

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • At the end of your answer you're telling that it fails with gcc version 10 and c++17. But that is the intended behavior since the restriction wasn't lifted in c++17 but only in c++20. – Jason Sep 16 '22 at 12:13
  • @JasonLiam Exactly, that's why it confirms my hypothesis that GCC deliberately enabled this from later standard versions onwards... – Columbo Sep 16 '22 at 12:20
3

Clang is wrong in rejecting the code as this is allowed by the standard. From temp.param#6:

6) A non-type template-parameter shall have one of the following (possibly cv-qualified) types:

6.1) a structural type (see below),

7) A structural type is one of the following:

7.2) an lvalue reference type, or

(emphasis mine)

This means that std::string& can be used as a nontype template parameter for which nameOk[0] is a valid nontype template argument and the program is well-formed.

Jason
  • 36,170
  • 5
  • 26
  • 60