模板定义非模板错误

Mar*_*sko 10 c++ templates generic-programming crtp

我想将CRTP模式与一些锁定机制结合使用,以便在多线程环境中进行访问同步.

我的代码看起来像这样:

//-- CRTP base class with some sync/lock mechanism
template<typename T, typename SYNC>
struct Base {
  static std::unordered_map<int, std::string> s_map;
  static SYNC s_sync;
};

//-- derived class using CRTP
template<typename SYNC>
struct ProductX : public Base<ProductX<SYNC>, SYNC> {};

//-- static initialisation
template<typename SYNC>
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map {
  { 1, "value_1" },
  { 2, "value_2" }
}
Run Code Online (Sandbox Code Playgroud)

但是我得到了

错误:非模板的模板定义 std::unordered_map<int, std::basic_string<char> > Base<ProductX<SYNC>, SYNC>::s_map

编译时

静态s_map初始化引发错误.有人能指出我做错了什么吗?

Col*_*mbo 8

Base<ProductX<SYNC>, SYNC>在定义中使用成员特化s_map,因此您实际上需要相应的部分特化Base(§14.5.5.3/ 1).换句话说,您正在尝试定义不存在的部分特化的成员.

尝试提供专业化:

template<typename SYNC>
struct ProductX;

//-- CRTP base class with some sync/lock mechanism
template<typename T, typename SYNC>
struct Base {};
template<typename SYNC>
struct Base<ProductX<SYNC>, SYNC> {
  static std::unordered_map<int, std::string> s_map;
  static SYNC s_sync;
};

//-- derived class using CRTP
template<typename SYNC>
struct ProductX : public Base<ProductX<SYNC>, SYNC> {};

//-- static initialisation
template<typename SYNC>
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map {
  { 1, "value_1" },
  { 2, "value_2" }
};
Run Code Online (Sandbox Code Playgroud)

演示.


n. *_* m. 5

一个简化的例子。

template <class A, class B>
struct C
{
    static int x;
};

template <class A, class B> int C<A, B>::x = 0; // this works
Run Code Online (Sandbox Code Playgroud)

然而

template <class A> int C<A, double>::x = 0; // same error as yours
Run Code Online (Sandbox Code Playgroud)

后一个定义属于不存在的 C 的部分特化。创建一个:

template <class A>
struct C<A, double>
{
    static int x;
};

template <class A> int C<A, double>::x = 1;
Run Code Online (Sandbox Code Playgroud)

一切都好起来了。


Mar*_*sko 0

C++ 允许这样做:

template<typename SYNC>
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { };
Run Code Online (Sandbox Code Playgroud)

仅具有相应的部分模板类专业化。为此,请查看下面 Columbo 和 nm 用户的回复。然而,缺点是您必须为以ProductX这种方式创建的每个类重新定义所有内容。IE。就我而言,如果我想创建类ProductX,,,,我将必须为它们中的每一个定义部分特化,包括所有成员函数等,恕我直言,这不是很实用ProductYProductZ

如果我们不想编写整个类的专业化,我们必须使用带有无规范模板定义的静态变量:

template<typename T, typename SYNC>
std::unordered_map<int, std::string> Base<T, SYNC>::s_map { };
Run Code Online (Sandbox Code Playgroud)

或完全专门的模板定义:

struct NoSync { };
template<typename NoSync>
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map { };
Run Code Online (Sandbox Code Playgroud)

这是具有完整模板专业化的完整示例:

//-- CRTP base class with some sync/lock mechanism
template<typename T, typename SYNC>
struct Base {
  static std::unordered_map<int, std::string> s_map;
  static SYNC s_sync;
  static std::string& value_name1(int value) { return s_map[value]; }
};

//-- derived class using CRTP
template<typename SYNC>
struct ProductX : public Base<ProductX<SYNC>, SYNC> {};

struct NoSync {};

//-- static initialisation
template<>
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map {
  { 1, "value_1" },
  { 2, "value_2" }
};

int main() {
  ProductX<NoSync> p;
  std::cout << "Value: " << p.s_map[1] << "\n";
  std::cout << "Value: " << p.value_name1(2) << "\n";
}
Run Code Online (Sandbox Code Playgroud)

这个可以编译得很好。

我要感谢 Columbo 和“nm”的回复并为我指明了正确的方向!我会选择您的答案,但我想在不编写类模板专业化的情况下展示此解决方案。