Зачем использовать SFINAE вместо перегрузки функций? - PullRequest
0 голосов
/ 25 февраля 2020

Я пытаюсь понять std::enable_if, есть пример на cppreference.com , в чем преимущество этого использования по сравнению с перегрузкой функции?

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

Ответы [ 2 ]

1 голос
/ 25 февраля 2020

Ваши два примера не совпадают. В первом примере класс будет исключать любое целочисленное значение или тип с плавающей запятой точно . Во втором примере вы берете int или float, то есть если вы передали long long или double, тогда у вас есть потенциал для сужающегося преобразования, которое может привести к потере данных. Это не имеет значения для кода, который вы используете, но за ним можно и нужно следить.

Вы также получите неоднозначности при использовании типа, который может быть преобразован в float или int. Например,

T1 foo{0l};

не будет компилироваться, но

T foo{0l};

будет.

0 голосов
/ 25 февраля 2020

В этом случае действительно нет никакого преимущества, потому что целочисленные типы будут сначала преобразованы, например, в int, а затем будет вызван правильный перегруженный конструктор.

Однако представьте, что вы хотите создать функцию который принимает только целые числа. Он должен вернуть тип целого числа, полученного в качестве аргумента. В этом случае создание> 10 перегрузок вручную просто подвержено ошибкам / глупо / раздражает / ... Вместо этого вы должны написать что-то вроде:

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