Что SFINAE?

Я увидел в нескольких вопросах, упомянутый слово SFINAE, не, если совсем в прописных буквах или как собственное имя: Sfinae.

Ища в Stackoverflow на Испанском языке я нахожусь, что даже есть документы стандарт, которые ссылаются на этот термин, как n3462 упомянутый в: Как знать версия стандарта C, что я использую в коде?, но из-за многого, что искал, я не вижу, что не говорилось ни о книжном магазине ни классе. Так что я осведомляюсь:

Что SFINAE?

8
задан 03.07.2017, 02:43
1 ответ

Чтобы начинаться, SFINAE - acr¦nimo:

S ubstitution F ailure I s N ot В n И rror.

Podr¦ - a быть переведенным как FESNEUE или FASNEUE:

F allo И n S ubstituci¦n N или И s Или n И rror.

F allo В l S ubstituir N или И s Или n И rror.

Для RAE acr¦nimo пишет себе в mayúsculas, если необходимо читать по складам это:

2.7. Инициалы и acr¦nimos

Инициалы и acr¦nimos, частота которой использования дала им carÃ: cter грамматический определенный - мужские или женские существительные, например, - они оказываются подобранными как нормальные поступающие данные (p. ej., радар), или в буквах mayúsculas, когда, обычно, необходимо читать по складам (ADN).

Ввиду того, что возможно читать с нормальностью (даже Английский versi¦n) я (лично) escribir¦ - в как будто это было нормальное слово, asà - что мы идем в reponder в вопрос...

Â: Qué - sfinae (fesneue/fasneue)?

- caracter¦-stica любопытные из функционирования шаблонов (template) C ++. Этот caracter¦-stica говорит нам, что бить козырем в заменять parÃ: у метра шаблона нет из-за qué быть ошибкой .

, Чтобы понимать это функционирование, мы можем видеть qué изюм с простым шаблоном:

template <typename T, typename U>
T plantilla(U u) { return static_cast<T>(u); }

, Когда мы используем предыдущий шаблон, шаблон перемещает из-за процесса instanciaci¦n , один из первых шагов состоит в том, чтобы заменять parÃ: метры genéricos (T и U в примере) из-за parÃ: пропорциональные метры (или пришедшие к заключению):

Замещать.

std::cout << plantilla<int, float>(123.456) << '\n';

В этом instanciaci¦n plantilla создает такой funci¦n как эта:

   int plantilla(float u) { return static_cast<int>(u); }
// ^^^           ^^^^^                         ^^^
//  T              U                            T

parÃ: метр genérico T был заменен int в то время как U был заменен float и imprimirÃ: 123 из-за консоли.

Â: Не удаваться!.

, Если мы меняем plantilla из следующего способа:

template <typename T, typename U>
T plantilla(typename U::value_type u) { return static_cast<T>(u); }
//          ^^^^^^^^  ^^^^^^^^^^^^ <--- referencia sub-tipo en U

, сделав предыдущим вызовом вытекающий substituci¦n serà ¡:

   int plantilla(typename float::value_type u) { return static_cast<int>(u); }
// ^^^                    ^^^^^                                     ^^^
//  T                       U                                        T

Ввиду того, что тип float не располагает подтипом value_type, substituci¦n бьет козырем и производит ошибку.

Â: Не удаваться!.

, Но если tuviéramos обе функции:

template <typename T, typename U>
T plantilla(typename U::value_type u) { return static_cast<T>(u); }

template <typename T, typename U>
T plantilla(U u) { return static_cast<T>(u); }

В instanciar шаблон tendr¦-хозяева versi¦n, который не удается, и другая, которая нет:

std::cout << plantilla<int, float>(123.456) << '\n';

// Fallo!
int plantilla(typename float::value_type u) { return static_cast<int>(u); }
// Correcto!
int plantilla(float u) { return static_cast<int>(u); }

В этом случае, составитель инстанция все шаблоны и попробуй заменять все parÃ: метры, если вслед за substituci¦n есть одна (и только одна) versi¦n vÃ: lida шаблона тогда не producirÃ: ошибка.

А именно, в этом случае мы смогли видеть, что F allo В l S ubstituir N или И s Или n И rror.

Стоит, я это понял, но... Â: для qué служи?

Поведение fasneue, составляет часть природы шаблонов C ++. Шаблоны diseñaron таким образом чтобы решать другие проблемы (как произвождение неожиданных ошибок, включив шаблоны librer¦-эксперта третьих), но какие-то программисты C ++ увидели добавочный потенциал в это поведение, так как он позволяет зачаточный introspecci¦n типов во времени compilaci¦n.

Например, если у нас есть funci¦n, который мы хотим, что actúe различным способом según, если он называется с números целые или с números в плавающей запятой:

void f(int)   { std::cout << "int\n"; }
void f(float) { std::cout << "float\n"; }

, назвав ее с типом, который не был бы int или float fallar¦ - в ambigüedad:

f(1u); // ERROR! Convierto unsigned int a int o a float?
f(.1); // ERROR! Convierto double a int o a float?

Возможный soluci¦n ser¦, - который должен создавать перегрузки для всех типов:

void f(char)               { std::cout << "entero\n"; }
void f(unsigned char)      { std::cout << "entero\n"; }
void f(signed char)        { std::cout << "entero\n"; }
void f(short)              { std::cout << "entero\n"; }
void f(unsigned short)     { std::cout << "entero\n"; }
void f(int)                { std::cout << "entero\n"; }
void f(unsigned int)       { std::cout << "entero\n"; }
void f(long)               { std::cout << "entero\n"; }
void f(unsigned long)      { std::cout << "entero\n"; }
void f(long long)          { std::cout << "entero\n"; }
void f(unsigned long long) { std::cout << "entero\n"; }
void f(float)              { std::cout << "flotante\n"; }
void f(double)             { std::cout << "flotante\n"; }
void f(long double)        { std::cout << "flotante\n"; }

- препятствие создавать 14 функций почти все равные с c¦digo повторенный, но с fesneue мы можем отделять эти функции в целом и плавающем:

template<class T, typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
void f(T) { std::cout << "entero\n"; }
template<class T, typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
void f(T) { std::cout << "flotante\n"; }

Две функции шаблон предыдущие позволяют различать, если полученный тип - целая стоимость или в плавающей запятой с так s¦lo две версии funci¦n, это помогаются других шаблонов получать:

Caracter¦-sticas типа <type_traits>.

Этот librer¦ - в ofrece шаблоны, которые они позволяют спрашивать в типы, чтобы проверять, выполняют ли они некие caracter¦-sticas, в часть" Â: Тип целый? " и" Â: Тип - плавающая запятая? " который уже мы увидели, могут быть использованными, чтобы подтверждать, - указатель, класс или funci¦n ли тип. Все эти так называемые шаблоны is_xxxx заканчиваются стоимостью booleano (вычисленный во времени compilaci¦n) с истинной стоимостью, если выполняется verificaci¦n.

Условный fesneue <std::enable_if>

Шаблон std::enable_if - объект, что, в случае когда condici¦n, полученный как первый parà выполняется: метр, contendrÃ: тип, облегченный как секунда parÃ: метр шаблона; в противоположном случае serÃ: объект vac¦ - или.


Зная это, último пример funcionar¦ - в о следующем способе:

template<class T, typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
void f(T) { std::cout << "entero\n"; }
template<class T, typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
void f(T) { std::cout << "flotante\n"; }

f(1u); // Muestra 'entero'
f(.1); // Muestra 'flotante'

В фазе substituci¦n, используя буквального целого числа без знака suceder¦ - в следующее:

  • std::is_integral_v<unsigned int> заменяется true.
  • std::enable_if_t<unsigned int, true> заменяется unsigned int.
  • funci¦n f остается как f(unsigned int).
  • std::is_floating_point_v<double> заменяется false.
  • std::enable_if_t<double, false> ничем не заменяется.
  • substituci¦n не удается.
  • выбирает первый versi¦n funci¦n как vÃ: lida.

Во втором случае, substituci¦n, который не удается, - первый и выбирается второй versi¦n funci¦n f, который не удался в substituci¦n.

9
ответ дан 30.10.2019, 01:00