11

$14.3.2 - "... A template-argument for a non-type, non-template template-parameter shall be one of:

...a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage..."

In the code shown below, I fail to understand why 'name2' and 'name3' are not allowed as non type template arguments. I am using gcc 4.7.2 on Windows.

Both 'name2' and 'name3' are names of array and hence are constant expressions. Further 'name2' is having internal linkage and 'name3' has both static and internal linkage.

template<char const *p> void f()
{

}

char name1[] = "Hi";
static char name2[]= "Hi";
const static char name3[]= "Hi";
char *name4 = "Hi";

int main()
{
    f<name1>();
    f<name2>();
    f<name3>();
    f<name4>();
}
Chubsdad
  • 24,777
  • 4
  • 73
  • 129

2 Answers2

5

As @Nawaz correctly guessed, this is an implementation bug, not an esoteric corner of the standard.

Specifically, gcc seems to have trouble with it. Barring the last name4 which is against the standard, the rest of it compiles fine with clang

Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • 1
    Guessed so. But now I am curious as to why string literals are not allowed. In C++03 they weren't allowed as they had internal linkage (as in C++11 too). So, String literals seem to satisfy all the criteria of the third bullet in this section – Chubsdad Jan 07 '13 at 10:14
  • @Chubsdad: string literals are not allowed probably because everytime you use a string literal of same value, they are not necessarily *identical* string i.e they might have different address. Means, `bool b = ("hello" == "hello")` *might* give you `false`! – Nawaz Jan 07 '13 at 10:18
  • @KonradRudolph: No, they're not allowed. See §14.3.2/1 (n3483). – Nawaz Jan 07 '13 at 10:18
  • 2
    @Nawaz Yes, of course. Blame R. Martinho in the chat, he mis-informed me. ;-) – Konrad Rudolph Jan 07 '13 at 10:21
  • 1
    +1 Goodness! I had not noticed that you could pick clang 3.2 on liveworkspace :D – Matthieu M. Jan 07 '13 at 13:00
  • @Nawaz: I have asked the question about string literals https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/DkDWRYQ4Vw0 – Chubsdad Jan 07 '13 at 13:20
  • @Chubsdad: Great! I believe you will get similar replies as I said in my previous comment, or at least that is one of the reason. Lets see what others say. – Nawaz Jan 07 '13 at 14:08
3

I think that the problem is that the expression you use are not actually pointers but arrays, and the pointer decay only works for name1. It is most likely a compiler bug, as kindly @KonradRudolph pointed out in the comment, section 14.3.2 of the C++11 standard allows it, and there is nothing essentially different between name1, name2 and name3.

As a workaround, the following will compile with GCC 4.7.2 using -std=c++11:

template<char const *p> void f()
{
}

char name1[] = "Hi";
static char name2[]= "Hi";
const static char name3[]= "Hi";

int main()
{
    f<(char const*)&name1>();
    f<(char const*)&name2>();
    f<(char const*)&name3>();
}

In C++98 mode it does not compile because the result of a cast is never a constant expression, while in C++11 it may be.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • Why shouldn’t automatic pointer decay work here? I suspect the compiler bug is the other way round. The arrays certainly have the correct linkage and are constant expressions; I see no reason why they shouldn’t work. – Konrad Rudolph Jan 07 '13 at 10:14
  • @KonradRudolph: You may very well be right! I cannot find in the standard any reference to automatic decay being used in constant expressions. Maybe it is implicitly specified elsewere, but I the constant expression requirements are a bit... let's say 'dense'. – rodrigo Jan 07 '13 at 10:19
  • @KonradRudolph: Right, it even gives an example similar to this one. Answer updated. – rodrigo Jan 07 '13 at 10:23