Почему это СФИНАЕ терпит неудачу? - PullRequest
0 голосов
/ 06 марта 2020
struct BLA
{

};


template<typename T>
class DUMMY
{
public:
    DUMMY() = default;

    template<typename U = T, typename = void>
    void someFunction()
    {
        std::cout << std::is_same<U, BLA>::value << "\n";
        std::cout << "someFunction() - DEFAULT\n";
    }

    template<typename U = T, typename std::enable_if<std::is_same<U, BLA>::value, void>::type>
    void someFunction()
    {
        std::cout << "someFunction()\n";
    }
};


int main()
{
    DUMMY<BLA> dummy;

    dummy.someFunction();
}

Почему этот код SFINAE вызывает someFunction (), который отображает "someFunction () - DEFAULT"? Стоит позвонить другому. Понятно, что std :: is_same :: value имеет значение true.

Ответы [ 2 ]

2 голосов
/ 06 марта 2020

template<typename U = T, typename std::enable_if<std::is_same<U, BLA>::value, void>::type> приведет (с правильной заменой) к template<typename U = T, void>, что недопустимо.

Вы можете изменить на

template<typename U = T, typename std::enable_if<std::is_same<U, BLA>::value, int>::type = 0>

, но тогда оба функция была бы жизнеспособной и столь неоднозначной.

Итак, вы, наконец, можете сделать

    template<typename U = T, typename std::enable_if<!std::is_same<U, BLA>::value, int>::type = 0>
    void someFunction()
    {
        std::cout << std::is_same<U, BLA>::value << "\n";
        std::cout << "someFunction() - DEFAULT\n";
    }

    template<typename U = T, typename std::enable_if<std::is_same<U, BLA>::value, int>::type = 0>
    void someFunction()
    {
        std::cout << "someFunction()\n";
    }

В C ++ 17 проще сделать

    void someFunction()
    {
        if constexpr (std::is_same<U, BLA>::value) {
            std::cout << "someFunction()\n";
        } else {
            std::cout << std::is_same<U, BLA>::value << "\n";
            std::cout << "someFunction() - DEFAULT\n";
        }
    }
0 голосов
/ 06 марта 2020

Я пишу как новый ответ, потому что он не подходит для комментариев. Для дополнения к @ Jarod42.

Кажется, вы предполагали, что

template<typename U = T, typename std::enable_if<std::is_same<U, BLA>::value, void>::type>

заменяет

template<typename U = T, typename = void>

, но это не так. Он заменяет

template<typename U = T, void>.

Итак, вы должны объявить его как

template<typename U = T, typename = typename std::enable_if<std::is_same<U, BLA>::value, void>::type>.

Поскольку typename, который вы использовали для указания типа, зависит, а не для объявления параметра шаблона , Но любой из них не будет работать так, как вы ожидали. Один бесшумно удаляет некорректное, другой приводит к многократному объявлению одной и той же функции.

После вашего комментария я пытаюсь объяснить более подробно.

template<typename U = T, typename std::enable_if<std::is_same<U, BLA>::value, void>::type>
void someFunction()
{
    std::cout << "someFunction()\n";
}

Если T == BLA, U становится BLA и составляет std::is_same< U , BLA>::value true. Таким образом, результат выглядит следующим образом:

template<typename U = BLA, void>

Если T == NotBlaType, U становится NotBlaType и составляет std::is_same<U,BLA>::value false. Результатом является ошибка подстановки, std::enable_if<false,void> не имеет type.

Но в обоих случаях функция не объявлена. Поскольку void не может быть разрешено как нетипизированный параметр шаблона .

Но если мы изменим void на int, то это будет разрешено. Вот почему @ Jarod42 предлагает int.

template<void> недопустимо.

Но template<int = 2> законно.

После того, как заявление объявлено правильно, вы должны условно переключать объявления функций (потому что обе функции имеют одинаковую подпись, поэтому вызывает многократное объявление). Вот почему обе функции в ответе @ Jarod42 имеют std::enable_if, что равнозначно отрицанию друг друга.

...