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
初始化引发错误.有人能指出我做错了什么吗?
您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)
演示.
一个简化的例子。
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)
一切都好起来了。
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
,,,,我将必须为它们中的每一个定义部分特化,包括所有成员函数等,恕我直言,这不是很实用ProductY
。ProductZ
如果我们不想编写整个类的专业化,我们必须使用带有无规范模板定义的静态变量:
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”的回复并为我指明了正确的方向!我会选择您的答案,但我想在不编写类模板专业化的情况下展示此解决方案。