我有以下代码:
#include <iostream>
#include <tuple>
class T
{
public:
using Names = std::tuple<char const*, char const*>;
static constexpr Names names {"First", "Second"};
};
int main()
{
std::cout << std::get<0>(T::names);
}
因为 names
是一个 constexpr
我希望它能工作。但是我收到链接器错误:
编译器:
> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
错误:
> g++ -std=c++1y pl.cpp
Undefined symbols for architecture x86_64:
"T::names", referenced from:
_main in pl-377031.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
最佳答案
static
的声明类中的数据成员永远不是定义1。
每当变量被 odr-used2 时,定义是必要的。
std::get<>
每个引用 接受参数,并将变量绑定(bind)到引用 odr-立即使用它3。
简单定义names
外面:
constexpr T::Names T::names; // Edit: This goes *outside* the class "as is"!
Demo .
1) [basic.def]/2:
A declaration is a definition unless [..] it declares a
static
data member in a class definition (9.2, 9.4)
2) [basic.def.odr]/4:
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.
3) 根据 [basic.def.odr]/3:
A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.19) that does not invoke any non-trivial functions and, ifx
is an object,ex
is an element of the set of potential results of an expressione
, where either the lvalue-to-rvalue conversion (4.1) is applied toe
, ore
is a discarded-value expression (Clause 5).
这里是 id-expression T::names
指的是有问题的变量。唯一的超表达式 e
包含 T::names
的所有潜在结果是T::names
本身,因为函数调用的潜在结果集,即 std::get<0>(T::names)
, 是空的。但是,显然没有应用左值到右值的转换,T::names
的值也显然没有被丢弃(因为它被传递给了一个函数)。
因此它是 odr-used 并且需要一个定义。
关于c++ - 静态元组类成员的 constexpr 有链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28134744/