I'm trying to pass a literal string as a template parameter in a C 14 project. Google told me that I can do as below:
struct Test {
static const char teststr[];
template<const char* str>
void p() {std::cout << str;}
};
const char Test::teststr[] = "Hello world!";
int main() {
Test t;
t.p<Test::teststr>();
}
It did work.
However, if I use const char*
, instead of const char []
. It won't work.
struct Test {
static const char* teststr;
template<const char* str>
void p() {std::cout << str;}
};
const char* Test::teststr = "Hello world!";
int main() {
Test t;
t.p<Test::teststr>();
}
Now it doesn't work. The compiler told me that 'Test::teststr' is not a valid template argument because 'Test::teststr' is a variable, not the address of a variable
.
Well, I don't know what it meant.
CodePudding user response:
This is just according to the rules of c :
Template non-type arguments.
For pointers to objects, the template arguments have to designate the address of a complete object with static storage duration and a linkage (either internal or external)
https://en.cppreference.com/w/cpp/language/template_parameters
A global array of characters has linkage while a string literal doesn’t.
In C 20 this has been changed and you can use string literals as template parameters.
CodePudding user response:
The error message from the compiler is clear enough:
error: 'Test::teststr' is not a valid template argument because 'Test::teststr' is a variable, not the address of a variable
So you need:
#include <iostream>
struct Test {
static const char* teststr;
template<const char **str>
void p() {std::cout << *str;}
};
const char* Test::teststr = "Hello world!";
int main() {
Test t;
t.p <&Test::teststr>();
}
And then it works - the point being that [the contents of] a variable is not a compile-time constant, whereas the address of a variable is.
CodePudding user response:
The problem is that in case 2 of your example the static data member teststr
is a pointer type that has the address of a string literal which is not allowed by the standard as can be seen from the quoted statement below ,
From non-type template parameter's documentation:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter. 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):
(1.1) a subobject (1.8),
(1.2) a temporary object (12.2),
(1.3) a string literal (2.13.5),
Thus, in case 2 of your example teststr
cannot be used as it is a pointer type that has the address of the string literal "Hello world!"
.