redkont
redkont

Reputation: 337

Why use SFINAE instead of function overloading?

I'm trying to understand std::enable_if , there is a example at cppreference.com , what is advantage of this using than function overloading ?

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              std::enable_if_t<std::is_integral<Integer>::value, int> = 0
    >
    T(Integer) : m_type(int_t) {}
> 
    template <typename Floating,
              std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0
    >
    T(Floating) : m_type(float_t) {} // OK
};


struct T1 {
        enum { int_t, float_t } m_type;
        T1(int) :m_type(int_t)
        {
            cout << "int ctor" << endl;
        }

        T1(float) :m_type(float_t)
        {
            cout << "float ctor" << endl;
        }
    };

Upvotes: 1

Views: 432

Answers (2)

NathanOliver
NathanOliver

Reputation: 180935

Your two examples are not the same. With the first example, the class will except any integer or floating point type exactly. With your second example, you only take in a int or float meaning if you passed a long long or doublethen you have the potential for a narrowing conversion which could cause you to lose data. That doesn't matter with the code you are using, but it can and should be watched out for.

You will also get ambiguities when using a a type that could be converted to either a float or an int. For example

T1 foo{0l};

wont compile but

T foo{0l};

will.

Upvotes: 1

AVH
AVH

Reputation: 11516

In this case there's indeed not really an advantage, because integer types would be converted to e.g. int first and then the correct overloaded constructor would be called.

However, imagine you want to create a function which only accepts integers. It should return the type of integer it received as argument. In that case manually creating >10 overloads is just error-prone/silly/annoying/... Instead, you'd write something like:

template <typename Integer,
          std::enable_if_t<std::is_integral<Integer>::value, int> = 0>
Integer doMagic (Integer a) {
  return a;
}

Upvotes: 0

Related Questions