2

我不得不从 g++-4.6 切换到 4.7(所以我可以使用一些 C++11 功能)。现在,编译器抱怨:

In function WordJIT<float>::WordJIT(): undefined reference to JitRegType<float>::Val_t

我想知道这些编译器版本之间是否发生了一些可能影响符号解析的变化。还是在新版本(4.7)中更好地实现了语言,而我正在做的事情是错误的:(相同的代码与 4.6 一起编译)

jit.h

class Jit {
  public:
    enum RegType { f32=0,f64=1,u16=2,u32=3,u64=4,s16=5,s32=6,s64=7 };
  // ...
};

template <class T> struct JitRegType {};
template <> struct JitRegType<float>  { static const Jit::RegType Val_t = Jit::f32; };

wordjit.h

  #include "jit.h"

  template<class T>
  class WordJIT 
  {
    WordJIT() {
      mapReg.insert( std::make_pair( JitRegType<T>::Val_t , jit.getRegs( JitRegType<T>::Val_t , 1 ) ) );
    }
    private:
      typedef std::map< Jit::RegType , int > MapRegType;
      mutable MapRegType mapReg;
  };

编辑:

可以在头文件中static const使用还是应该使用?constexpr

有没有办法Val_t在类声明中声明JitRegType但实际上没有定义它?

4

1 回答 1

5

根据 9.4.2p3:

如果非易失性const 静态数据成员是整数或枚举类型,则其在类定义中的声明可以指定一个大括号或相等初始化器[...] 如果它是,则该成员仍应在命名空间范围内定义程序中使用的 odr 和命名空间范围定义不得包含初始化程序

所以你需要添加到你的程序中(可能在jit.cpp):

const Jit::RegType JitRegType<float>::Val_t;

这样一来,如果在static const需要对其进行引用的上下文中使用该成员,则存在一个唯一的定义供链接器引用(与任何static不是类模板或类模板部分成员的成员相同)专业化)。

该问题在 gcc wiki 上进行了深入讨论。

请注意,gcc 4.6 和 4.7 的行为都很合理;只是 gcc 4.6 选择内联JitRegType<float>::Val_tgcc 4.7 选择不内联的值(或者可能是内联它,但也发出对定义的链接器引用)。很难判断是否需要实施才能发出诊断;9.4.2p3 描述了一个可诊断的规则,但随后 9.4.2p4(隐含地指非const static数据成员)说不需要诊断。无论哪种方式,作为实现质量问题,编译器发出诊断总比不发出诊断要好。

于 2012-10-12T13:52:18.883 回答