This question already has an answer here:
I'm trying to find a comfortable way to pass string literals as template arguments. I'm not caring about supporting the widest possible number of compilers, I'm using the latest version of g++ with --std=c++0x
.
I've tried a lot of possible solutions but all have disappointed me. I'm sort of giving up, but first I'd like to know why a couple of them failed.
Here they are:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
char const *operator () () const {
return m_sz;
}
};
template<class _rstr>
string const Get() {
return _rstr();
}
int main() {
cout << Get<String("hello")>() << endl;
return 0;
}
And:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
int main() {
String constexpr str = "hello";
cout << Get<str>() << endl;
return 0;
}
The goal was to find a comfortable way to pass a string literal to the useless Get function, which returns its template argument as an std::string object.
EDIT: sorry, maybe my main question isn't clear. My question is: why do those two snippets fail?
You can "simulate" strings with C++11 variadic templates:
This prints:
You can't use string literals as a template argument, for the simple reason that it's unspecified whether two instances of a literal with the same text are the same object or not. In other words, given:
It would be unspecified whether
v1
andv2
had the same type or not.You can use
char const[]
variables as template arguments, however, since they have a defined address:In this case,
v1
andv2
are guaranteed to have the same type.EDIT:
I think C++11 removes the need for the
extern
on the definition of the string, at least if the string and the instantiation are all in the same translation unit. I'm not sure, however; the one time I did something like this, I didn't have access to C++11.re: your OP:
I'd like to know why a couple of them failed.
The comment by @NatanReed is correct:
Get
needs aTYPE
and is given anobject
.reference to an object
became legal.Template arguments must be constants from a limited set of types.
And even then, the
String constexpr str = "hello";
must have external linkage. So putting it on the stack inside ofmain()
is not going to work.Give this a try:
I know the post is old but I haven't found any solution for this problem here, and maybe someone would be interested in my workaround:
Now usage:
Unfortunately one have to provide the length of the string to get it work but it's still more comfortable solution than plain variadic arg template of chars, and the length is verified by the static_assert so the compiler can help to pick appropriate value...
Edit
One more template magic. This one is making use of short-circuit to get rid of the string size from STRING_LITERAL declaration (c++17):
[live demo]