通过模板模板参数使用枚举标记对象
Tagging objects using enums via template-template parameters
我想使用模板的枚举参数,来限制第二个参数,一个类,反过来接受枚举成员作为模板参数的参数。在代码中,我希望它看起来像:
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)),错误信息:
来源。cc:16:45:错误:' SUBOBJECT_TAG '未在此范围内声明struct 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的模板参数一致,我计划(如果可能的话)通过模板特化或默认参数自动完成。
我指定这个对象层次结构的目标还包括:
- 避免强制这个库的用户定义额外的类或结构
- 利用编译时间检查使用枚举模板化CObject,其函数反过来使用该枚举枚举作为所有对象通用的一组函数的参数
template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T
的参数是模板,而不是模板的实例。CSubObject<blah>
不能匹配template<...>class
类型,因为CSubObject<blah>
是模板生成的类型,而不是模板。template<...>class
参数是模板,不是类型。
另外,CSubObject
是template<class T, T> class
的同类,而不是template<SUBOBJECT_TAG_T>class
。它接受两个参数,第一个是类型,第二个是该类型的常量:template<SUBOBJECT_TAG_T>class
类型是一个模板,它接受一个SUBOJECT_TAG_T
类型的参数。这些是不相关的模板。
第二,你似乎在模板专门化方面有问题。模板专门化是主专门化的模式匹配。它们不是"新的超载"。因此,CObject
的参数必须首先匹配CObject
的主要专门化所期望的参数类型。template< blah >
中的内容用于模式匹配专门化CObject< blah >
部分中的模式。
一般来说,习惯上只对宏使用ALL CAPS,而对模板参数则不使用。
这些都是你问题中代码的问题。你的代码缺乏一个清晰的问题陈述或疑问,所以我能做的最好的就是描述你无数问题的修复方法。
你的问题修改了一点。
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> >
我做了一些修改使它可以编译。虽然我不能100%确定这是否真的做了你想要的它做的;我同意雅克在他的回答中所说的大部分。
注意:下面的将不能编译,因为我故意尝试将一种枚举类型与另一种枚举的值混合,以验证它确实会触发编译时错误,我认为这正是您所要求的。
#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;
}
- C++ 使用枚举类对象分配 std::map 值
- 将枚举传递到不同文件中的对象中
- 枚举 QQmlEngine 中的所有对象
- 如何在V8中为C 本机对象实现属性枚举器
- 从对象访问结构枚举
- 如何使用枚举元素创建对象
- 如何在 c++ 中使用枚举参数实例化对象
- 虚拟方法返回代表派生对象类型的枚举 - 是否可以(在设计方面)
- 对象、枚举类型和范围的问题
- 无法获取库上的枚举(未定义的引用静态元对象)
- Qt、枚举和元对象编译器
- 构造构造函数采用单个枚举参数的临时对象时出错
- C++ dynamic_cast vs 将对象类型存储在静态枚举中
- gtest枚举和对象之间的比较
- 在C++中创建一个具有随机枚举类型的Card对象
- 通过模板模板参数使用枚举标记对象
- 枚举<T>所有 T 的所有 SomeClass 对象
- 枚举对象名称
- 成员对象中枚举的行为
- 赋给c++中对象类项的枚举值