【问题标题】:Undefined reference when changing from GCC 4.6 to 4.7从 GCC 4.6 更改为 4.7 时未定义的引用
【发布时间】:2012-10-12 13:10:53
【问题描述】:

我不得不从 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

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

【问题讨论】:

  • reg 中的reg( JitRegType&lt;T&gt;::Val_t ); 是什么?
  • @PiotrNycz 我用它代替了占位符,以免过多地破坏示例。但是,见上文
  • 您在切换到 gcc 4.7 但停留在 C++03 时是否收到错误,或者您是否还启用了 C++11?因为如果您选择相同的 C++ 标准版本,名称解析在两个版本中的实现应该完全相同,因为它们应该根据标准实现它。
  • -std=c++0x 在 4.6 和 4.7 中均启用。我在代码的其他部分通常需要 C++11 功能。现在我正在使用构造函数委托 - 切换到 4.7 的原因
  • 肮脏的解决方法:让reg(...) 接受一个int 而不是RegType,或者强制转换它。但是,如果有人知道这在 4.6 中起作用而在 4.7 中不起作用的原因会更好......

标签: c++ static c++11 constants


【解决方案1】:

每 9.4.2p3:

如果一个非易失的const static数据成员是整数或枚举类型,它在类定义中的声明可以指定一个brace-or-equal-initializer [ ...] 如果成员在程序中被 odr-used 并且命名空间范围定义不应包含 initializer,则该成员仍应在命名空间范围内定义。

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

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

这样,如果 static const 成员在需要引用它的上下文中使用,则存在一个唯一的定义供链接器引用(与任何不是类模板或类模板部分特化的成员)。

该问题已深入讨论on the gcc wiki

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

【讨论】:

  • @Frank gcc 4.6 内联该值(它可以从标头访问它)并且不发出对它的链接器引用。严格来说,您的程序在没有定义的情况下是格式错误的,即使 gcc 4.6 编译它也是如此。
  • 哇!了解这一点很重要。切换到 4.7 时可能会破坏大量代码,这显然更严格地实现了该语言。非常感谢!!
猜你喜欢
  • 2011-05-14
  • 1970-01-01
  • 2013-11-19
  • 1970-01-01
  • 2014-04-21
  • 2012-12-12
  • 2013-01-10
  • 1970-01-01
  • 2018-05-07
相关资源
最近更新 更多