C ++ SFINAE enable_if_t в функции-члене, как устранить неоднозначность? - PullRequest
0 голосов
/ 29 августа 2018

Предположим, у нас есть некоторая функция-член SFINAE:

class foo{
    template <class S, class = std::enable_if_t<std::is_integral<S>::value, S>
    void bar(S&& s);
    template <class S, class = std::enable_if_t<!std::is_integral<S>::value, S>
    void bar(S&& s);
}

Если мы объявили это, как указано выше, то как мы можем их определить? Обе сигнатуры их функций выглядят так:

template <class S, class>
inline void foo::bar(S&& s){ ... do something ... }

Я видел примеры, когда каждый возвращает std::enable_if_t<...> вроде:

template <class S, class>
auto bar(S&& s) -> std::enable_if_t<!std::is_integral<S>::value, S>(...){
    ... do something ...
}

Для устранения неоднозначности на основе типа возвращаемого значения. Но я не хочу ничего возвращать.

Ответы [ 3 ]

0 голосов
/ 29 августа 2018

С компилятором C ++ 11 другой вариант - использовать диспетчеризацию тегов.

template <class S>
void bar(S&& s)
{
    bar(std::forward<S>(s), std::is_integral<S>{});
}

template <class S>
void bar(S&& s, std::true_type)
{
    ... 
}

template <class S>
void bar(S&& s, std::false_type)
{
    ... 
}
0 голосов
/ 29 августа 2018

Вы все еще можете сделать это в типе возврата просто отлично. Просто оставьте значение по умолчанию enable_if (то есть void). Даже если вы только на C ++ 11, просто добавьте этот псевдоним:

template <bool B, typename T=void>
using enable_if_t = typename std::enable_if<B, T>::type;

И тогда вы можете сделать:

template <class S>
enable_if_t<std::is_integral<S>::value>
bar(S);

template <class S>
enable_if_t<!std::is_integral<S>::value>
bar(S);

Или:

template <class S>
auto bar(S) -> enable_if_t<std::is_integral<S>::value>

template <class S>
auto bar(S) -> enable_if_t<!std::is_integral<S>::value>

В любом случае, у вас есть две правильно устраненные неоднозначности функции, которые возвращают void.

0 голосов
/ 29 августа 2018

поскольку аргументы по умолчанию не являются частью сигнатуры функции, сделайте их не по умолчанию

class foo{
    template <class S, typename std::enable_if<std::is_integral<S>::value, int>::type = 0>
    void bar(S&& s);
    template <class S, typename std::enable_if<!std::is_integral<S>::value, int>::type = 0>
    void bar(S&& s);
};

Live Demo


РЕДАКТИРОВАТЬ: по многочисленным просьбам, вот тот же код в C ++ 17:

class foo{
public:
    template <class S>
    void bar(S&& s)
    {
        if constexpr(std::is_integral_v<S>)
            std::cout << "is integral\n";
        else
            std::cout << "NOT integral\n";
    }
};

constexpr, если операторы являются специальными для компилятора, потому что ветвь выбрана во время компиляции, а не взятая ветвь даже не создана

C ++ 17 Демо

...