问题
#include <iostream>
using namespace std;
template<typename T> void print(T&& mX)
{
std::cout << std::forward<T>(mX) << std::endl;
}
struct SomeStruct
{
static constexpr const char* someString{"hello!"};
SomeStruct()
{
print(someString);
}
};
int main()
{
SomeStruct s{};
return 0;
}
clang++ -std=c++1y ./code.cpp -o code.o
/tmp/code-a049fe.o: In function `SomeStruct::SomeStruct()': ./code.cpp:(.text._ZN10SomeStructC2Ev[_ZN10SomeStructC2Ev]+0xa): undefined reference to `SomeStruct::someString' clang: error: linker command failed with exit code 1 (use -v to see invocation)
g++ -std=c++1y ./code.cpp -o code.o
/tmp/ccyrTsjS.o: In function `SomeStruct::SomeStruct()': code.cpp:(.text._ZN10SomeStructC2Ev[_ZN10SomeStructC5Ev]+0xd): undefined reference to `SomeStruct::someString' collect2: error: ld returned 1 exit status
Why is this linker error happening? Isn't someString
supposed to be resolvable at compile-time?
Also, the error doesn't happen if print(someString)
is replaced with cout << someString;
回答1:
Because you are taking a reference the variable is odr-used and this requires a definition out of line:
constexpr const char* SomeStruct::someString;
see it working live.
From the draft C++14 standard section 3.2
[basic.def.odr]:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any nontrivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression [...]
For example the following alternative print
would not odr-use someString
:
template<typename T> void print(T mX)
{
std::cout << mX << std::endl;
}
回答2:
There are a narrow set of circumstances under which you may not bother to define a static
data member (whether it's constexpr
or not, and whether it takes advantage of this initialisation form or not), and this is not one of them, because you indirectly take the address of it (and therefore it must exist as an actual object in memory).
You can kind of think of it as a static data member that can't simply be "inlined" at the point of its use, due to what that use is.
Define someString
.
来源:https://stackoverflow.com/questions/28839672/linker-error-undefined-reference-with-static-constexpr-const-char-and-perfe