2015-07-22 139 views
9

我想将CRTP pattern与某些锁定机制结合使用以在多线程环境中进行访问同步。非模板错误的模板定义

我的代码如下所示:

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

但是我得到

error: template definition of non-template std::unordered_map<int, std::basic_string<char> > Base<ProductX<SYNC>, SYNC>::s_map

编译时。

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

+0

@Deduplicator - 这不是你标记的内容的重复。如果重复的东西,那么这一个:http://stackoverflow.com/questions/13404695/c-how-to-initialize-static-variables-of-a-partial-template-specialization –

回答

0

C++允许这样的:

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

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

如果我们不想写全班专业化,我们必须使用静态变量,没有规范的模板定义:

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

这一个将编译好。

我想感谢Columbo和'n.m.'为他们的答复,并指出我在正确的方向!我会选择你的答案,但我想显示这个解决方案,而不写类模板专业化。

+0

Col ** u ** mbo。中间有一个你。 – Columbo

+1

@Columbo除非他是[斯里兰卡](https://en.wikipedia.org/wiki/Colombo)粉丝... – Barry

+0

@Barry我很欣赏研究,但我的名字仍然是科伦坡。我不叫你贝瑞,因为我喜欢瞎闹。 ;-) – Columbo

7

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

Demo

+0

谢谢你的回答科伦坡!你是对的,并指出我正确的方向。但是,对于我而言,编写模板类专业化并不是很方便,因为我必须为每个创建的ProductX重写所有内容。有关更多详情,请参阅下面的答案。 –

4

一个简化的例子。

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 

后者定义属于哪个不存在℃的部分特。创建一个:

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

template <class A> int C<A, double>::x = 1; 

一切都很好。

+0

感谢您的回答!作为科伦坡,你指出了我的正确方向。有关更多详细信息,请参阅我自己的答案 –