`static constexpr const char*` 和完美转发的链接器错误(未定义引用)
Linker error (undefined reference) with `static constexpr const char*` and perfect-forwarding
#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
为什么会出现此链接器错误? someString
不应该在编译时解析吗?
此外,如果将 print(someString)
替换为 cout << someString;
,则不会发生错误
因为你正在引用变量是 odr-used 并且这需要一个不合时宜的定义:
constexpr const char* SomeStruct::someString;
来自 C++14 标准草案部分 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 [...]
例如,下面的替代方案 print
不会 odr-use someString
:
template<typename T> void print(T mX)
{
std::cout << mX << std::endl;
}
在极少数情况下,您可能懒得定义一个 static
数据成员(无论它是否是 constexpr
,也不管它是否利用了这种初始化形式),这不是其中之一,因为您间接获取了它的地址(因此它必须作为内存中的实际对象存在)。
你可以把它想象成一个静态数据成员,在使用时不能简单地是 "inlined",因为 what 使用是。
定义someString
.
#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
为什么会出现此链接器错误? someString
不应该在编译时解析吗?
此外,如果将 print(someString)
替换为 cout << someString;
因为你正在引用变量是 odr-used 并且这需要一个不合时宜的定义:
constexpr const char* SomeStruct::someString;
来自 C++14 标准草案部分 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 [...]
例如,下面的替代方案 print
不会 odr-use someString
:
template<typename T> void print(T mX)
{
std::cout << mX << std::endl;
}
在极少数情况下,您可能懒得定义一个 static
数据成员(无论它是否是 constexpr
,也不管它是否利用了这种初始化形式),这不是其中之一,因为您间接获取了它的地址(因此它必须作为内存中的实际对象存在)。
你可以把它想象成一个静态数据成员,在使用时不能简单地是 "inlined",因为 what 使用是。
定义someString
.