我有一些我不理解的链接问题。
以下是来源:
#include <iostream>
template < typename T >
struct CompressedEnums {
CompressedEnums () : data(0) {}
T get() const {
return (T)(data);
}
void set(const T& value) {
data = value;
}
unsigned data;
};
namespace Bbs_detail {
enum inner_type { BB0 = 0 , BB1 = 1 , BB2 = 2 };
typedef inner_type E;
};
struct Bbs {
static const size_t size = 3;
typedef Bbs_detail::inner_type inner_type;
typedef inner_type E;
static const Bbs_detail::E BB0 = Bbs_detail::BB0;
static const Bbs_detail::E BB1 = Bbs_detail::BB1;
static const Bbs_detail::E BB2 = Bbs_detail::BB2;
};
std::ostream& operator<<(std::ostream& o, const Bbs::E& e) {
switch(e) {
case Bbs::BB0: o << "BB0"; return o;
case Bbs::BB1: o << "BB1"; return o;
case Bbs::BB2: o << "BB2"; return o;
}
return o;
};
int main(int argc, const char *argv[]) {
CompressedEnums< Bbs::E > l;
l.set(Bbs::BB0);
Bbs::E x = l.get();
std::cout << x << std::endl;
return 0;
}
当我使用-O3编译它时它可以工作,但是我用-O0得到了链接器错误。我已经尝试过使用gcc 4.6.2和gcc 4.7。
使用clang 3.0进行编译时,无论优化级别如何,都会出现链接器错误。
链接器错误:
/tmp/cch116DO.o: In function `main':
test.cxx:(.text+0x8f): undefined reference to `Bbs::BB0'
collect2: error: ld returned 1 exit status
这是因为我做了非法行为吗?
我认为整数类型的静态const成员可以在课堂上初始化,不是吗?
答案 0 :(得分:3)
引用C ++ 98标准, 9.4.2静态数据成员:
如果静态数据成员是const integer或const枚举类型,则它在类定义中的声明可以指定一个常量初始化器,它应该是一个整型常量表达式(5.19)。在这种情况下,成员可以出现在整数常量中。 如果在程序和命名空间中使用该成员,则仍应在命名空间范围内定义该成员 范围定义不应包含初始化程序。 [强调我的]。
所以你必须定义常数成员是Alan Stokes在他的回答中指出的。如果你不这样做,并且编译器设法避免对变量的任何引用,因为它是常量并且它已经知道了值,你可能没有它。但不保证这一点。
在C ++ 11草案中非常奇怪,还有一些关于constexpr
和大括号初始化器的附加说明,然后:
如果程序中的成员使用(3.2),该成员仍应在名称空间范围中定义。
然后,在第3.2点中,它定义 odr-used 的含义:
名称显示为潜在评估表达式的变量是 odr-used ,除非它是满足出现在常量表达式(5.19)和左值到右值的要求的对象转换(4.1)立即应用。
也就是说,在C ++ 11中,如果对常量成员的所有使用都是常量表达式,则可以保证不需要成员定义:
答案 1 :(得分:1)
如果声明类的静态成员,则还需要在一个源文件中定义它。
(通常你可以在不这样做的情况下离开,但并非总是如此,标准要求它。)
所以你需要的地方
const Bbs_detail::E Bbs::BB0;
等