SFINAE for specialization of traits on CRTP struct

I am tryng to specialize some traits (for instance std::is_arithmetic or assertion_traits in cppunit) for a template class (CRTP) that can hold a value of the template parameter type (something similar to BOOST_STRONG_TYPEDEF )

I try to use SFINAE to restrict my specialization

the sample code works fine with gcc6 and upper, but does not compile with Visual c++ (2015 or 2017)

error C2753: 'is_ar<T>': partial specialization cannot match argument list for primary template

or clang6

error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

the sample code:

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");

What did i do wrong ?

Is it valid c++11 ? How can I make it work with Visual C++ compiler ?

the answer from max66 work fine assuming that I can modify the initial definition of the trait. but in practice i would like to specialize framework traits (cppunit::assertion_traits for instance) for the class created by the macro

#define MY_TYPEDEF(type , base) struct type: Base<type , base> { };

the classes declared by this macro are not template classes so I do not find a way to specialize for all the classes generated this way.

The only common denominator beeing the typenames base_type and typed_type being defined.

Any Idea ?


[meta.type.synop:1]
The behavior of a program that adds specializations for any of the templates defined in this subclause is undefined unless otherwise specified.

That subsection includes std::is_arithmetic , so unfortunately you are not allowed to make this specialization at all.


The error from the compiler is saying the is_arithmetic specialization isn't actually specializing the template. When the conditions are met, and removing the clutter, it reads

template<typename T>
struct is_arithmetic<T> : is_arithmetic<typename T::base_type> {};

To specialize, you may specialize it for your Base

template<typename T, typename B>
struct is_arithmetic<Base<T, B>> : is_arithmetic<B> {};

It is illegal to specialize is_arithmetic


Frankly, I don't know if is right g++ or clang++.

Anyway, I don't think is a good idea specialize a standard class is forbidden specialize std::arithmetic (see Quentin's answer).

To avoid this sort of problems, I suggest you to define another (not-standard) type-traits, say isAr , as follows

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

Now

static_assert(isAr<CRTPInt>::value, "failed");
static_assert(isAr<CRTPInt::base_type>::value, "failed");

compile with both g++ and clang++.

-- EDIT --

For your modified example, my suggestion become

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/90836.html

上一篇: 从析构函数中抛出异常

下一篇: SFINAE用于CRTP结构特征的专业化