SFINAE用于CRTP结构特征的专业化
我尝试着为一个模板类(CRTP)专门化一些特征(例如std :: is_arithmetic或cppunit中的assertion_traits),该模板类可以保存模板参数类型的值(类似于BOOST_STRONG_TYPEDEF
)
我尝试使用SFINAE来限制我的专业化
示例代码可以正常使用gcc6和upper,但不能用Visual c ++(2015或2017)进行编译,
error C2753: 'is_ar<T>': partial specialization cannot match argument list for primary template
或clang6
error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
示例代码:
template<class T, typename B>
struct Base
{
using typed_type = T ;
using base_type = B ;
base_type x;
};
template <typename T>
struct MyType
{
using base_type = T;
base_type x;
};
struct CRTPInt : Base<CRTPInt, int> { };
template <typename T>
struct is_ar
{
static const bool value = false;
};
template <>
struct is_ar<int>
{
static const bool value = true;
};
template <class T, typename...>
using typer = T;
template <typename T>
struct is_ar<typer<T, typename T::base_type, typename T::typed_type>> : is_ar<typename T::base_type>
{
static const bool value = true;
};
static_assert(is_arithmetic<CRTPInt>::value, "failed");
static_assert(is_arithmetic<CRTPInt::base_type>::value, "failed");
我做错了什么 ?
它有效的C ++ 11? 我如何使它与Visual C ++编译器一起工作?
假设我可以修改特征的初始定义,max66的答案很好。 但在实践中,我想专门为宏由宏创建类的框架特征(例如cppunit :: assertion_traits)
#define MY_TYPEDEF(type , base) struct type: Base<type , base> { };
由这个宏声明的类不是模板类,所以我没有找到一种方法专门为这种方式生成的所有类。
唯一常见的分母是定义的类型名称base_type和typed_type。
任何想法 ?
[meta.type.synop:1]
除非另有说明,否则为本子条款中定义的任何模板添加专业化的程序的行为均未定义。
该小节包括std::is_arithmetic
,所以不幸的是你不允许做这个专业化。
编译器的错误是说is_arithmetic
专门化实际上并没有专门化模板。 当条件满足时,清除混乱,它读取
template<typename T>
struct is_arithmetic<T> : is_arithmetic<typename T::base_type> {};
为了专业化,你可以专门为你的Base
template<typename T, typename B>
struct is_arithmetic<Base<T, B>> : is_arithmetic<B> {};
专门研究is_arithmetic
是非法的
坦率地说,我不知道g ++或clang ++是否正确。
无论如何,我不认为是一个好主意,专门化一个标准类是禁止特殊化std::arithmetic
(请参阅Quentin的答案)。
为了避免这种问题,我建议你定义另一个(非标准)类型特征,如isAr
,如下所示
template <typename T, typename = T>
struct isAr : public std::is_arithmetic<T>
{ };
template <typename T>
struct isAr<T, typer<T, typename T::base_type, typename T::typed_type>>
: public isAr<typename T::base_type>
{ };
现在
static_assert(isAr<CRTPInt>::value, "failed");
static_assert(isAr<CRTPInt::base_type>::value, "failed");
用g ++和clang ++编译。
- 编辑 -
对于你修改的例子,我的建议变成了
template <typename T, typename = T>
struct isAr : public std::false_type
{ };
template <>
struct isAr<int> : public std::true_type
{ };
template <typename T>
struct isAr<T, typer<T, typename T::base_type, typename T::typed_type>>
: public isAr<typename T::base_type>
{ };
static_assert(isAr<CRTPInt>::value, "failed");
static_assert(isAr<CRTPInt::base_type>::value, "failed");
链接地址: http://www.djcxy.com/p/90835.html