X 的任何子类的专用类模板,无需向模板添加其他类型参数
Specializing class template for any subclass of X without adding an additional type argument to the template
我需要专业化
template< typename T, int Id >
struct ValueTraits
{
// Default version
static int getValue() { return 0; }
};
对于某些ConcreteClass
的任何子类,T
:
class ConcreteClass {};
struct ConcreteSub1: public ConcreteClass
{
static int get() { return 1; }
};
struct ConcreteSub2: public ConcreteClass
{
static int get() { return 2; }
};
对于Id
的某个预定值,比如123
,
。这样ValueTraits< ConcreteSub1, 123 >::getValue()
会调用ConcreteSub1::get()
并返回1
,而ValueTraits< ConcreteSub2, 123 >::getValue()
会调用ConcreteSub2::get()
并返回2
。使用除 123
以外的任何Id
或除 ConcreteClass
子类以外的类应回退到模板的默认版本。
现在,我知道我可以将std::enable_if
与std::is_base_of
一起使用,但这不需要向ValueTraits
添加一个额外的虚拟类型参数吗?像这样的东西会起作用,例如:
#include <stdio.h>
#include <type_traits>
template< typename T, int Id, typename Dummy = void >
struct ValueTraits
{
// Default version
static int getValue() { return 0; }
};
class ConcreteClass {};
struct ConcreteSub1: public ConcreteClass
{
static int get() { return 1; }
};
struct ConcreteSub2: public ConcreteClass
{
static int get() { return 2; }
};
template< typename T >
struct ValueTraits< T, 123, typename std::enable_if<
std::is_base_of< ConcreteClass, T >::value >::type >
{
static int getValue() { return T::get(); }
};
int main()
{
// prints 1, 2, 0
printf( "%d, %d, %dn",
ValueTraits< ConcreteSub1, 123 >::getValue(),
ValueTraits< ConcreteSub2, 123 >::getValue(),
ValueTraits< int, 123 >::getValue() );
return 0;
}
问题是,我无法向ValueTraits
添加额外的虚拟类型参数,因为它是库的一部分,该库实际上为我提供了这种专攻ValueTraits
。
所以我的问题是,我可以用原始版本的ValueTraits
只typename
和int
来执行这种专业化吗?
编辑:澄清一下,我也不是ValueTraits
的用户 - 库为我提供了专门化,然后库再次使用我的类型实例化它,以获得我在专业化中定义的行为。所以我既不能控制ValueTraits
的定义,也不能控制之后的使用方式。
GCC 4.8+ 可以,但不能 Clang:
template< typename T >
struct ValueTraits< T, std::enable_if<std::is_base_of< ConcreteClass, T >::value,
std::integral_constant<int, 123> >::type::value >
{
static int getValue() { return T::get(); }
};
我倾向于认为 Clang 目前是对的,但 CWG 1315 可能会更改此处的规则,以便上述代码变得有效,因此如果您只需要它来在 GCC 4.8 或更高版本上工作,您可能是安全的。
有趣的问题,但如果您提供一些额外的用例或更多信息,它会更有帮助,因为它的使用方式可能会改变实现的细节。
好的,现在回到答案,所以考虑到那里有一个你不能在这里修改的库,你可以这样做:
首先有一个你想要的任何形状或形式的类:
template< typename T, typename Dummy>
struct MyOwnSpecializedClassInAnyWayIWant
{
// your own specialization:
static int getValue() { return 0; }
};
现在,您只需要专攻一次ValueTraits
:
template< typename T , typename Dummy = void >
struct ValueTraits < MyOwnSpecializedClassInAnyWayIWant<T, Dummy> >
{
// Default version
static int getValue() { return MyOwnSpecializedClassInAnyWayIWant<T, Dummy>::getValue(); }
};
用例如下所示:
ValueTraits< MyOwnSpecializedClassInAnyWayIWant< ConcreteSub1 >>::getValue()
现在这样写有点痛苦,所以你可以使用:
template <class T>
using ValueTraits_t = ValueTraits< MyOwnSpecializedClassInAnyWayIWant< T > >;
//use ValueTraits_t<ConcreteSub1>;
作为旁注,为了简单起见,我删除了Id
,但这也可以使用它。
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- "std::shared_ptr":不是参数"_Ty"的有效模板类型参数
- 具有可变参数非类型参数的模板专用化
- 函数类型参数的模板参数推导
- PowerShell 使用结构类型参数调用 C++ DLL 的导出函数
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 为模板传递非类型参数 agument
- 为什么带有类型参数的运算符 () 可以应用于 result_of 上下文中的类型?
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 如何避免具有相同类型参数的函数中的错误
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- c++非类型参数包扩展
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 在不同的模板参数包之间分发非类型参数包
- 如何在使用容器和字符串时强制使用显式分配器类型参数
- 错误:一元"*"的类型参数无效(具有"int"):使用 mergesort 计算
- 为什么重写方法并将 const 添加到参数类型有效
- X 的任何子类的专用类模板,无需向模板添加其他类型参数
- 在模板参数的方法中添加类型转换时出现clang错误