std :: enable_if против серьезных ошибок в не непосредственном контексте - PullRequest
0 голосов
/ 10 апреля 2020

В соответствии с описанием SFINAE на cpprefence

Только сбои в типах и выражениях в непосредственном контексте типа функции или ее типов параметров шаблона или ее явных спецификатор (начиная с C ++ 20) - это ошибки SFINAE. Если оценка замещенного типа / выражения вызывает побочный эффект, такой как создание некоторой специализации шаблона, генерация неявно определенной функции-члена и т. Д. c, ошибки в этих побочных эффектах рассматриваются как серьезные ошибки.

В частности, когда Helper<T> в моем коде ниже создается во время вывода аргумента шаблона, я получаю ошибку, как и ожидалось. Итак, вот мой вопрос: почему std::enable_if хорошо работает с SFINAE, несмотря на то, что это структура, для которой необходимо создать экземпляр (и обычно используется со множеством структур типа-признаков, которые также создаются в процессе).

Вот код

#include<iostream>
#include<type_traits>

template<typename T, typename U = typename T::my_type>
void sfinae(const T&) { std::cout << "template\n"; }

void sfinae(...) { std::cout << "non template\n"; }

template<typename T>
struct Helper{
    using my_type = typename T::my_type;
};

template<typename T, typename U = typename Helper<T>::my_type>
void hardError(const T&) { std::cout << "template\n"; }

void hardError(...) { std::cout << "non template\n"; }


struct NonEmpty{ using my_type=int; };
struct Empty{ };


int main()
{
    NonEmpty ne;
    Empty e;

    sfinae(ne);     //template overload called
    hardError(ne);  //template overload called

    sfinae(e);      //non-template overload called

    hardError(e);   //hard error 

}

1 Ответ

2 голосов
/ 10 апреля 2020

Возможная реализация для std::enable_if -

template <bool cond, typename T = void> struct enable_if;
template <typename T> struct enable_if<false, T>{};
template <typename T> struct enable_if<true, T>{ using type = T; };

Так что enable_if не вызывает серьезных ошибок. экземпляр std::enable_if<false> действителен.

Создание экземпляра Helper<Empty> приводит к ошибке Empty::type, которая не выполняется в непосредственном контексте SFINAE , поэтому серьезная ошибка.

std::enable_if и std::void_t хорошо работают с SFINAE, поскольку они обеспечивают простой способ сбоя в ближайшем контексте:

std::enable_if<cond_v<T>, int>::type = 0 или typename AlwaysVoid = std::void_t<decltype(dependent_expression)>.

...