我有一堆类有一个静态成员,它是一个枚举值。我在其他地方有一张 map ,以这个枚举为键。现在,如果我在函数中使用模板参数来访问 map ,我会得到一个 undefined reference 。
为了清楚起见,这里是一个简化的非工作示例:
template<int T>
struct A
{
static const int Type = T;
}
template<class T>
void fun()
{
cout << map_[T::Type] << endl;
}
map<int, string> map_{{1337, "1337"}};
主要内容:
fun<A<1337>();
给我(g++ 4.7):
undefined reference to `(anonymous namespace)::A<1337>::Type'
但是这样:
template<class T>
void fun()
{
auto key = T::Type;
cout << map_[key] << endl;
}
编译并打印1337
谁能给我解释一下这种行为?
最佳答案
当您使用 T::Type
时,您必须定义它:
template<int T>
struct A
{
static const int Type = T;
}
template <int T>
const int A<T>::Type;
是的,即使您在 A<T>
内提供了它的内联初始化程序!
您可能没有意识到这一点的原因与您在第二种情况下没有遇到相同问题的原因相同——由于立即从左值到右值的转换,标准允许编译器优化引用Type
的要求在运行时,能够在编译时挑选出值。然后链接器就不需要搜索定义,你也不会出错。
[C++11: 9.4.2/2]:
The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static data member shall be qualified by its class name using the :: operator. The initializer expression in the definition of a static data member is in the scope of its class (3.3.7). [..]
[C++11: 9.4.2/3]:
If a non-volatileconst static
data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.19). Astatic data
member of literal type can be declared in the class definition with theconstexpr
specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.
[C++11: 3.2/2]:
[..] A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. [..]
关于C++ 模板类静态常量变量成员作为映射键给出 undefined reference ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16730336/