GCC 向依赖默认构造函数的模板化类中的静态数据成员提供“未定义引用”错误

And*_*rew 5 c++ gcc templates static-members c++11

我有一个与此类似的问题:

静态字段模板特化的“未定义引用”

但他们使用的解决方法对我不起作用。

我有一个带有静态数据成员的 CRTP 类,其中一个是 std::mutex。不幸的是,GCC 的 (4.8.2) 链接器给了我这个互斥锁的“未定义引用”错误。Clang (3.4) 没有。有解决方法吗?最初的问题(上面链接)在静态数据成员上调用了复制构造函数,迫使 GCC 发出一个符号,但由于我的数据成员是 std::mutex,这不是一个选项——复制构造函数被删除,然后没有参数构造函数。我只是被冲洗了吗?

我不相信问题出在 std::mutex 上,我认为问题在于 GCC 如何处理依赖默认构造函数的模板类中的静态数据成员。

谢谢你的帮助!

这是我的问题的精简版:test.hh

#include <mutex>

template < class T >
class CRTP_class {
public:
  T * ptr_;
  static std::mutex mutex_; // linker error here
  static int clearly_a_problem_with_mutex_; // no linker error here
};

class Foo : public CRTP_class< Foo >
{
public:
  void set_bar( int setting );
  int bar_;
};
Run Code Online (Sandbox Code Playgroud)

测试.cc

#include <test.hh>

template<> std::mutex CRTP_class< Foo >::mutex_;
template<> int CRTP_class< Foo >::clearly_a_problem_with_mutex_( 0 );

void Foo::set_bar( int setting ) {
  std::lock_guard< std::mutex > locker( mutex_ );
  ++clearly_a_problem_with_mutex_;
  bar_ = setting;
}
Run Code Online (Sandbox Code Playgroud)

主文件

#include <test.hh>

int main() {
  Foo foo;
  foo.set_bar( 5 );
}
Run Code Online (Sandbox Code Playgroud)

然后我用这个命令编译:

g++ -std=c++0x main.cc test.cc -I.
Run Code Online (Sandbox Code Playgroud)

得到错误

/tmp/cclyxUfC.o: In function `Foo::set_bar(int)':
test.cc:(.text+0x86): undefined reference to `CRTP_class<Foo>::mutex_'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

(编辑 1:回应评论者,他认为这是一个重复的错误,“为什么模板必须在头文件中”——将单独的模板专业化放入 .cc 文件而不是放入.hh 文件——如果你有一个互斥锁,并且出于显而易见的原因,你只需要该互斥锁的一个副本,这正是你所需要的。如果你在头文件中声明了一个静态数据成员,那么#includes 标头的每个翻译单元最终都将拥有自己的互斥锁副本,在这种情况下,它无法确保互斥的工作)

(编辑 2:糟糕!我链接到错误的先前错误。)

And*_*rew 4

来自 GCC 的 Jonathan Wakely 在 bugzilla 上的发言:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63876

问题似乎是我没有为互斥体提供初始化程序。其语法是提供左花括号和右花括号

template<> std::mutex CRTP_class< Foo >::mutex_;
Run Code Online (Sandbox Code Playgroud)

变成

template<> std::mutex CRTP_class< Foo >::mutex_{};
Run Code Online (Sandbox Code Playgroud)

(将互斥锁存在于 .cc 文件中没有问题)