【问题标题】:Tagging objects using enums via template-template parameters通过模板模板参数使用枚举标记对象
【发布时间】:2015-10-26 02:50:20
【问题描述】:

我想使用模板的枚举参数来限制第二个参数,一个类,反过来将枚举的成员作为参数作为模板参数。在代码中,我希望它看起来像:

CObject<EObjectTag, CSubObject<EObjectTag::CAT_A>> cObject;

这应该可以,但是:

CObject<EObjectTag, CSubObject<ENotAnObjectTag::CAT_OTHER>> cObject;

应该失败,因为ENotAnObjectTag::CAT_OTHER 不是EObjectTag 的元素。

我的实现(尝试)如下,并在编译期间(在 gcc 版本 4.9.2(Ubuntu 4.9.2-10ubuntu13)上)出现错误消息:

source.cc:16:45:错误:“SUBOBJECT_TAG”未在此范围内声明 结构 CObject>

#include <iostream>
#include <typeinfo>

enum class EObjectTag {CAT_A, CAT_B, CAT_OTHER};

// CSubObject
template<class OBJECT_TAG_T, OBJECT_TAG_T OBJECT_TAG>
struct CSubObject { OBJECT_TAG_T m_tTag = OBJECT_TAG; };

// CObject - Forward declaration
template <class SUBOBJECT_TAG_T, template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T>
struct CObject;

// CObject - Specialization
template <class SUBOBJECT_TAG_T, template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T>
struct CObject<SUBOBJECT_T<SUBOBJECT_TAG_T, SUBOBJECT_TAG>>
{
   public:
      SUBOBJECT_T<SUBOBJECT_TAG_T, SUBOBJECT_TAG> m_cSubObject;
};

int main() {
   // The aim is that the second object only accepts a tag that 
   // belongs to EObjectTag
   CObject<EObjectTag, CSubObject<EObjectTag::CAT_A>> cObject;

   return 0;
}

最后一个用例涉及将 CSubObject 替换为 CObject,以便我们可以使用递归来定义标记对象的层次结构,这也需要使用可变参数模板来在同一级别拥有多个对象。例如:

/* EBase, */
CObject</*EBase::BASE,*/ EObject,
    CObject<EObject::INIT, EInitObject,
        CObject<EInitObject::INIT_FOO>,
        CObject<EInitObject::INIT_BAR>,
    >,
    CObject<EObject::COUNT, ECountObject,
        CObject<ECountObject::COUNT_FOO>,
        CObject<ECountObject::COUNT_BAR>,
    >,
> cMyObjectHierarchy;

注释掉的对 EBase(库内部的枚举)的引用是为了保持 CObject 的模板参数一致,我会计划(如果可能)通过模板特化或默认参数自动执行此操作。

我指定此对象层次结构的目标还包括:

  1. 避免强制此库的用户定义其他类 或他们程序中的结构
  2. 利用编译时间检查通过 使用枚举对 CObject 进行模板化,其函数又使用该枚举 枚举作为所有 CObject 共有的一组函数的参数

【问题讨论】:

  • 请描述清楚的问题陈述或问题。你有不明确的目标(尽可能利用编译时检查等),但没有什么明确。我可以(并且已经)描述了您的代码的无数问题,但这并不能让我们接近解决您的实际问题,因为您的实际问题尚不清楚。您似乎有一个目标,并且您生成了一堆无法解决它的代码,但这并没有传达您的目标是什么。
  • @Yakk 感谢您的反馈,我已经更新了问题第一部分的措辞并删除了最后一部分,因为它与我的问题确实相关。

标签: c++ templates c++11 enums template-templates


【解决方案1】:

template &lt;SUBOBJECT_TAG_T SUBOBJECT_TAG&gt; class SUBOBJECT_T 的参数是模板,而不是模板的实例。 CSubObject&lt;blah&gt; 无法匹配 template&lt;...&gt;class 类型,因为 CSubObject&lt;blah&gt; 是由模板生成的 type,而不是模板。 template&lt;...&gt;class 参数是模板,而不是类型。

此外,CSubObject 类似于 template&lt;class T, T&gt; class,而不是 template&lt;SUBOBJECT_TAG_T&gt;class。它接受两个参数,第一个是类型,第二个是该类型的常量:template&lt;SUBOBJECT_TAG_T&gt;class 是一个模板,它接受一个 SUBOJECT_TAG_T 类型的参数。这些是不相关的模板类型。

其次,您似乎对模板专业化有疑问。模板专业化是您的主要专业化的模式匹配。它们不是“新的重载”。所以CObject 的参数必须首先匹配CObject 的主要特化所期望的参数类型。 template&lt; blah &gt; 中的内容用于模式匹配专业化的CObject&lt; blah &gt; 部分中的模式。

一般来说,通常只对宏使用全大写,而不是模板参数。

这些都是您问题中代码的问题。您的代码缺少明确的问题陈述或问题,所以我能做的最好的就是描述对您无数问题的修复。


你已经稍微修改了你的问题。

template<class T, class U>
struct CObject;

template<class T, template<class Q, Q>class Z, T t>
struct CObject< T, Z<T, t> > {
};

live example.

现在,您仍然需要传递 CSubObject&lt;EObjectTag, EObjectTag::CAT_A&gt; 作为第二个参数。

您还可以添加专业化:

template<class T, template<T>class Z, T t>
struct CObject< T, Z<t> > {
};

如果你有template&lt;EObjectTag tag&gt; struct Example;,你也可以CObject&lt; EObjectTag, Example&lt;EObjectTag::bob&gt; &gt;

【讨论】:

  • 我正在研究这种解决问题的方法。这很好,但是必须使用:template&lt;EObjectTag tag&gt; struct Example; 定义一个结构,因为它需要对需要定义的每种类型的枚举都进行此定义...
  • @allsey 您的要求仍然含糊不清。没有提到定义这样一个结构是您想要避免的事实。我仍然不知道为什么你有“子对象”类型。
  • 我再次更新了问题并将主要用例添加到最后。很抱歉修改了这么多,但由于这是一个关于设计的问题,所以将用例与我的核心问题分离是非常具有挑战性的
【解决方案2】:

我进行了一些更改以使其编译。虽然我不能 100% 确定这是否真的做到了你想要它做的事情;我同意 Yakk 在他的回答中所说的大部分内容。

注意:以下将编译,因为我故意尝试将一个枚举的类型与另一个枚举的值混合以验证它确实触发了编译时错误,我认为这是你要求的那种。

#include <iostream>
#include <typeinfo>

enum class EObjectTag {CAT_A, CAT_B, CAT_OTHER};
enum class FObjectTag {DOG_A, DOG_B, DOG_OTHER};

// CSubObject
template<typename OBJECT_TAG_T, OBJECT_TAG_T OBJECT_TAG>
struct CSubObject { OBJECT_TAG_T m_tTag = OBJECT_TAG; };

// CObject - Specialization
template <class SUBOBJECT_TAG_T, SUBOBJECT_TAG_T SUBOBJECT_TAG, template <typename TYPE_T, TYPE_T TYPE> class SUBOBJECT_T>
struct CObject
{
   public:
      SUBOBJECT_T<SUBOBJECT_TAG_T, SUBOBJECT_TAG> m_cSubObject;
};

int main() {
   // The aim is that the second object only accepts a tag that 
   // belongs to EObjectTag
   CObject<EObjectTag, EObjectTag::CAT_A, CSubObject> cObject1;
   CObject<EObjectTag, FObjectTag::DOG_B, CSubObject> cObject2;

   return 0;
}

【讨论】:

  • 感谢您的回复,我之前也遇到过类似的情况,但不幸的是,将枚举值移到类模板参数之外并不是一个合理的解决方案。这是因为它通过可变参数模板防止了未指定数量的参数,其中不支持交替值和类型参数...
  • 我已更新问题以提高清晰度并优化我的用例
猜你喜欢
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多