2

Why the second function can't match the template in the class definition??

    Class C {        
            template <typename T, typename T2 = T>
            T val() const;
        };

        template <>
        std::string C::val() const { 
             //OK
        }

        template <typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
        T C::val() const {
            //Not OK
        }

EDIT: This is an overview of what I want to achieve. Basically I'm writing a function to parse and return an object based on the template type. I have some defined classes of my own, that is I have to parse with respect to their members. I also need to parse numerical types and to strings. So I wrote a specialized version for every of my defined classes. A version that parses to numerical types and return the given type (of course I have to make sure that the given type is numerical, hence the enable if)

mkmostafa
  • 3,071
  • 2
  • 18
  • 47

1 Answers1

4

To utilize SFINAE, use it in the template declaration, not specialization:

class C {
    template <typename T, typename T2 = typename std::enable_if<std::is_arithmetic<T>::value>::type>
    T val() const;
};

If you want to differentiate between arithemtic and non-arithmetic types (allowing both), you can utilize tagging:

class C {
public:
    struct arithmetic_tag {};
    struct non_arithmetic_tag {};

    template <typename T>
    T val(typename std::conditional<std::is_arithmetic<T>::value, arithmetic_tag, non_arithmetic_tag>::type tag = {}) const
    {
        return get_val<T>(tag);
    }

private:
    template <typename T>
    T get_val(C::non_arithmetic_tag) const;

    template <typename T>
    T get_val(C::arithmetic_tag) const;
};

Or delegate the specialization to a helper class:

class C {
public:
    template <typename T>
    T val() const
    {
        return ValGetter<T>::get(this);
    }

private:
    template <typename T, bool is_arithmetic = std::is_arithmetic<T>::value>
    struct ValGetter;
};

// Arithmetic
template <typename T>
struct C::ValGetter<T, true>
{
    static T get(C const* c);
};

// Non-arithmetic
template <typename T>
struct C::ValGetter<T, false>
{
    static T get(C const* c);
};

EDIT: partial specializations (bool parameter) do not work for methods, shown tagging and helper classes instead

StenSoft
  • 9,369
  • 25
  • 30
  • I would like to understand why it does not work like this. I thought that enable_if returns the type of T in the end so it should work with the current definition – mkmostafa Apr 13 '16 at 12:38
  • @mkmostafa It does not work because for non-arithmetic types, it does not have `type` defined and SFINAE does not work for specializations. – StenSoft Apr 13 '16 at 12:40
  • @StenSoft This is a parial struct/class specialization not a method this is a huge difference – W.F. Apr 13 '16 at 12:45
  • but I would like to differntiate between arithmetic, classes inherited from specific base (is_base_of) and the rest. is there any other elegant solution than having to add these bool types everytime? – mkmostafa Apr 13 '16 at 12:45
  • @WojciechFrohmberg Methods can't have partial specializations – StenSoft Apr 13 '16 at 12:50
  • 1
    @WojciechFrohmberg Oh, right. It needs tagging instead. I will update the answer. – StenSoft Apr 13 '16 at 12:56
  • @mkmostafa Not for methods. But you can make dummy classes/structs that the methods will call and these can use `std::enable_if`. – StenSoft Apr 13 '16 at 13:04