【问题标题】:Template definition of non-template error非模板错误的模板定义
【发布时间】:2015-10-11 23:28:17
【问题描述】:

我想将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" }
}

但是我得到了

错误:非模板std::unordered_map&lt;int, std::basic_string&lt;char&gt; &gt; Base&lt;ProductX&lt;SYNC&gt;, SYNC&gt;::s_map的模板定义

编译时。

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

【问题讨论】:

标签: c++ templates generic-programming crtp


【解决方案1】:

您使用Base&lt;ProductX&lt;SYNC&gt;, SYNC&gt; 作为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.

【讨论】:

  • 感谢您的回答哥伦布!你是对的,并为我指明了正确的方向。但是,在我的情况下,编写模板类专业化并不是很方便,因为我必须为我创建的每个 ProductX 重写所有内容。有关详细信息,请参阅下面的答案。
【解决方案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;

一切都好起来了。

【讨论】:

  • 感谢您的回答!作为哥伦布,你为我指明了正确的方向。有关详细信息,请参阅下面我自己的答案。
【解决方案3】:

C++ 允许这样做:

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

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

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

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.'感谢他们的回复并为我指明了正确的方向!我会选择你的答案,但我想在不编写类模板专业化的情况下展示这个解决方案。

【讨论】:

  • Columbo。中间有个你。
  • @Columbo 除非他是Sri Lanka 的粉丝...
  • @Barry 我很欣赏这项研究,但我的名字仍然是 Columbo。我也不是因为我喜欢荆棘而称你为“贝瑞”。 ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 2020-12-17
  • 1970-01-01
相关资源
最近更新 更多