1

Some code that I don't understand:

template<const char *T>
class A
{
};

const char *arr="hello world";

int main()
{
    A<arr> obj;
}

This snippet won't compile.

Error message from visual studio compiler is :

Invalid template argument for 'A', expected compile-time constant expression

Error messega from g++ is:

'arr' is not a valid template argument because 'arr' is a variable , not the address of a variable

For visual studio compiler, even after I change the const to constexpr, that code still doesn't compile.

Why is that? Is that relevant to those internal linkage and external linkage thing?(I read this from the book C++ template, but don't understand why and how)

Additionally, change the const char *arr = "Hello world"; to

const char arr[] = "Hello world";

or

external const char *arr="Hello world";

won't work.

But this would work:external const char arr[]="Hello world";

walkerlala
  • 1,599
  • 1
  • 19
  • 32

2 Answers2

2

The issue is simpler than you're making it. The Visual Studio compiler's error message is actually quite clear. arr is not a valid template argument because it is not a compile-time constant.

In order to use a string as a template non-type parameter, it must be a variable with external linkage (although C++11 does, I believe, remove this requirement—see Columbo's answer). So you could change your code to the following, and it would work:

template <const char* T>
class A
{
   // ...
};

extern const char arr[] = "hello world";

int main()
{
    A<arr> obj;
}

Note how the declaration of arr has changed. The variable is now a named object with external linkage, and so it can be used as a template non-type parameter.

Basically, what happens is its address is passed to the template. This means that it is not the content of the string that determines its uniqueness, but the object itself. In other words, if you had two different variables that held exactly the same string, they would nevertheless have different types and create two different instantiations of the template class.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
1

Template parameters of pointer type are not allowed to refer to string literals ([temp.arg.nontype]/(1.3)). Instead, declare a global array:

constexpr char arr[] = "hello world"; // Or use const only, but won't be able to
                                      // use it inside the template

This can be used as a template argument, since it can appear in constant expressions and has static storage duration, making it a permitted result of a constant expression ([expr.const]/5).

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • I'm pretty sure that the `constexpr` declaration doesn't actually matter here, and will trip up a compiler that doesn't support C++11. The important part is that the object has external linkage. – Cody Gray - on strike Jan 14 '16 at 11:28
  • @CodyGray No. We're talking C++11, were linkage is completely irrelevant. See [temp.arg.nontype]. The `constexpr` is relevant as per [expr.const]/(2.7.3)- take a look. – Columbo Jan 14 '16 at 11:29
  • Ah, I see. Yeah, I knew that things had changed in C++11, but I'm stuck on a compiler that has very limited if any support, so my knowledge is kind of out of date. I don't have a copy of the standard in front of me, but I found [this answer](http://stackoverflow.com/a/30604988/366904) very useful. – Cody Gray - on strike Jan 14 '16 at 11:34
  • @CodyGray Yep, that author's answers are very comprehensive :-) – Columbo Jan 14 '16 at 11:37