0

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

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

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

/* 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 共有的一组函数的参数
4

2 回答 2

2

的参数template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T是模板,而不是模板的实例。 CSubObject<blah>无法匹配 kind template<...>class,因为CSubObject<blah>是模板生成的类型,而不是模板。 template<...>class参数是模板,而不是类型。

另外,CSubObject是种template<class T, T> class,不是template<SUBOBJECT_TAG_T>class。它有两个参数,第一个是类型,第二个是该类型的常量: kindtemplate<SUBOBJECT_TAG_T>class是一个模板,它接受一个 type 的参数SUBOJECT_TAG_T。这些是不相关的模板类型。

其次,您似乎对模板专业化有疑问。模板专业化是您的主要专业化的模式匹配。它们不是“新的重载”。因此,参数CObject必须首先匹配CObject预期的主要专业化的参数类型。里面的东西template< blah >用于模式匹配CObject< blah >专业化部分的模式。

通常,只对宏使用全部大写字母,而不对模板参数使用是惯例。

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


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

template<class T, class U>
struct CObject;

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

活生生的例子

现在,您仍然必须CSubObject<EObjectTag, EObjectTag::CAT_A>作为第二个参数传递。

您还可以添加专业化:

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

如果你有一个template<EObjectTag tag> struct Example;,你也可以CObject< EObjectTag, Example<EObjectTag::bob> >

于 2015-10-23T15:22:09.527 回答
1

我进行了一些更改以使其编译。虽然我不能 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;
}
于 2015-10-23T15:31:21.040 回答