通过模板-模板参数使用枚举标记对象
Tagging objects using enums via template-template parameters
我想使用模板的枚举参数来限制第二个参数,class,进而将枚举的成员作为参数作为模板参数。在代码中,我希望它看起来像:
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: error: ‘SUBOBJECT_TAG’ was not declared in this scope
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 的模板参数一致,我计划(如果可能)通过模板特化或默认参数自动执行此操作。
我指定此对象层次结构的目标还包括:
- 避免强迫该库的用户定义额外的 classes
或他们程序中的结构
- 通过
使用枚举对 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
的参数。这些是不相关的模板。
其次,您似乎对模板专业化有疑问。模板专业化是您的主要专业化的模式匹配。他们不是 "new overloads"。因此 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> >
。
我做了一些修改使其可以编译。尽管我不能 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;
}
我想使用模板的枚举参数来限制第二个参数,class,进而将枚举的成员作为参数作为模板参数。在代码中,我希望它看起来像:
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: error: ‘SUBOBJECT_TAG’ was not declared in this scope 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 的模板参数一致,我计划(如果可能)通过模板特化或默认参数自动执行此操作。
我指定此对象层次结构的目标还包括:
- 避免强迫该库的用户定义额外的 classes 或他们程序中的结构
- 通过 使用枚举对 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
的参数。这些是不相关的模板。
其次,您似乎对模板专业化有疑问。模板专业化是您的主要专业化的模式匹配。他们不是 "new overloads"。因此 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> >
。
我做了一些修改使其可以编译。尽管我不能 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;
}