模板定义的非模板错误

Template definition of non-template error

本文关键字:错误 定义      更新时间:2023-10-16

我想在多线程环境中结合使用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" }
}

但是我得到

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

编译时

静态s_map初始化引发错误。谁能指出我哪里做错了吗?

您使用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" }
};

一个简化的例子。

template <class A, class B>
struct C
{
    static int x;
};
template <class A, class B> int C<A, B>::x = 0; // this works
然而

template <class A> int C<A, double>::x = 0; // same error as yours

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

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

一切都好。

c++允许:

template<typename SYNC>
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map { };

只能使用相应的部分模板类特化。要做到这一点,请查看下面哥伦布和n.m.用户的回应。然而,缺点是您必须为您以这种方式创建的每个ProductX类重新定义所有内容。Ie。在我的情况下,如果我想创建类ProductX, ProductY, ProductZ,我将不得不为它们中的每一个定义部分专门化,包括所有成员函数等,这不是很实用IMHO。

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

template<typename T, typename SYNC>
std::unordered_map<int, std::string> Base<T, SYNC>::s_map { };

或完全专门化的模板定义:

struct NoSync { };
template<typename NoSync>
std::unordered_map<int, std::string> Base<ProductX<NoSync>, NoSync>::s_map { };

下面是完整模板专门化的完整示例:

//-- 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";
}

这个可以很好地编译。

我要感谢哥伦布和n.m。感谢他们的回答,并为我指出了正确的方向!我会选择你的答案,但我想在不编写类模板专门化的情况下展示这个解决方案。