将错误与静态const值链接,引用替代命名空间中的枚举

时间:2012-02-09 15:44:05

标签: c++ linker

我有一些我不理解的链接问题。

以下是来源:

#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成员可以在课堂上初始化,不是吗?

2 个答案:

答案 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;