SFINAE с шаблонными функциями-членами класса - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь узнать о SFINAE и столкнулся с проблемой при попытке применить его к функциям-членам класса шаблона.Благодаря Почему SFINAE (enable_if) не работает для функций-членов шаблона класса? Мне удалось настроить базовый пример ( Запустить онлайн ):

template<typename T>
class Foo{
    public:
    template <typename U = T, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int> = 0>
    void sfinae() { // Foo<anything else>
        std::cout << "sfinae default" << std::endl;
    }

    template <typename U = T, typename std::enable_if_t<std::is_same<U, int>::value,int> = 0>
    void sfinae() { // Foo<int>
        std::cout << "sfinae int" << std::endl;
    }

    template <typename U = T, typename std::enable_if_t<std::is_same<U, float>::value,int> = 0>
    void sfinae() { // Foo<float>
        std::cout << "sfinae float" << std::endl;
    }
};

У меня было два дополнительных вопроса к этому:
1. Как я могу разделить объявление и определение функций-членов?
Я попробовал что-то подобное ниже для определения:

template <typename T>
template <typename U = T, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int> = 0>
    void Foo<T>::sfinae() { // Foo<anything else>
        std::cout << "sfinae default" << std::endl;
    }

Но это дает ошибку компиляции.

2. Регистрируемый регистр по умолчанию (который печатает sfinae-default) в настоящее время должен быть записан как not(type1, type2,...), который потенциально может быть огромным.Возможно ли более короткое / более чистое решение?

Редактировать : На основе ответа @Jans вот исправленное решение .

1 Ответ

0 голосов
/ 11 декабря 2018

В вне строки определения вы удаляете аргументы по умолчанию, они взяты из объявлений:

template <class T>
template <typename U, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int>>
void Foo<T>::sfinae() { // Foo<anything else>
    std::cout << "sfinae default" << std::endl;
}

то же самое для остальных

регистр по умолчанию для всех ловушек (который печатает sfinae-default) в настоящее время должен быть записан как not(type1, type2,...), что потенциально может быть огромным.Возможно ли более короткое / более чистое решение?

Для этого вам нужно добавить дополнительный параметр для ранжирования перегрузок, дающий наименьший ранг универсальному, это обычно делается с использованием того факта, чтопараметр многоточия не лучше, чем любой другой тип параметра:

template <typename U = T>
void sfinae(...);

template <typename U = T, typename std::enable_if_t<std::is_same<U, int>::value,int> = 0>
void sfinae(int);

template <typename U = T, typename std::enable_if_t<std::is_same<U, float>::value,int> = 0>
void sfinae(int);

Foo<char>{}.sfinae(0); // select the catch-all

Это означает, что, поскольку ... хуже, чем любой другой параметр (int лучше, чем ...), перегрузкаsfinae(...) рассматривается только в том случае, если два других не могут быть вызваны, т. Е. Если они СФИНАЕ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...