I've written this beauty:
#include <iostream>
struct something {
static const char ref[];
};
const char something::ref[] = "";
template<int N, const char(&t_ref)[N], typename to> struct to_literal {
private:
static to hidden[N];
public:
to_literal()
: ref(hidden) {
for(int i = 0; i < N; i++)
hidden[i] = t_ref[i];
}
const to(&ref)[N];
};
template<int N, const char(&ref)[N], typename to> const to* make_literal() {
return to_literal<N, ref, to>().ref;
}
int main() {
const wchar_t* lit = make_literal<sizeof(something::ref), something::ref, wchar_t>();
}
It somewhat cleanly converts between string literal types. But when I compile it, MSVC says that the make_liter开发者_如何学JAVAal function is an undefined external function- which is clearly untrue as it's defined right there.
Edit: I've managed to reduce the problem down without all of the template gunk.
struct some {
friend int main();
private:
static wchar_t hidden[40];
public:
some()
{
}
};
int main() {
std::cout << some::hidden;
//const wchar_t* lit = make_literal<sizeof(something::ref), something::ref, wchar_t>();
}
main.obj : error LNK2001: unresolved external symbol "private: static wchar_t * some::hidden" (?hidden@some@@0PA_WA)
It's just a static array. Does life hate me?
The issue is that is that to_literal::hidden
is declared but never defined. Take another look:
struct something {
static const char ref[]; // declaration of something::ref
};
const char something::ref[] = ""; // definition of something::ref
template<int N, const char(&t_ref)[N], typename to> struct to_literal {
private:
static to hidden[N]; // declaration of to_literal::hidden (but there's no
// definition anywhere)
public:
to_literal()
: ref(hidden) {
for(int i = 0; i < N; i++)
hidden[i] = t_ref[i];
}
const to(&ref)[N];
};
To fix this, add a proper definition of to_literal::hidden
:
template<int N, const char(&t_ref)[N], typename to>
to to_literal<N, t_ref, to>::hidden[N]; // definition of to_literal::hidden
When you define static members, a declaration does not suffice. You must provide a definition outside the class. I.e. add
wchar_t some::hidden[40];
outside the class, and it'll be defined.
Otherwise, if C++ allowed this, it'd cause the same problem as defining a global variable in a header -- every .cpp file that includes it will come with a duplicate definition, and at link time you'd get a multiply-defined symbol error.
You're declaring but not defining the static member. Add something like...
template<int N, const char(&t_ref)[N], typename to>
to to_literal<N, t_ref, to>::hidden[N];
I tried to check in MSVC for you too, but with VS2005 I get another stupid error...
template<int N, const char(&t_ref)[N], typename to>
to to_literal<N, t_ref, to>::hidden[N];
...compiler complains of...
error C3860: template argument list following class template name must list parameters in the order used in template parameter list
Looks like when they fix one bug, there's another one behind it ;-/.
When I built this with VC 2008, that wasn't the error I got. The error was:
Error 1 error LNK2001: unresolved external symbol "private: static wchar_t * to_literal<1,&public: static char const * const something::ref,wchar_t>::hidden" (?hidden@?$to_literal@$00$1?ref@something@@2QBDB_W@@0PA_WA) main.obj Enabler
Removing static
from the to hidden[N];
member resolved the issue.
Are you sure you got the error message correct?
精彩评论