Jump to content

Отказ замены не является ошибкой

(Перенаправлено из Sfinae )

Отказ замены не является ошибкой ( sfinae ) является принципом в C ++, где неверная замена параметров шаблона сама по себе не является ошибкой. Дэвид Вандевоорд впервые представил аббревиатуру Sfinae для описания связанных методов программирования. [ 1 ]

В частности, при создании кандидата, установленного для разрешения перегрузки , некоторые (или все) кандидаты этого набора могут быть результатом экземплярных шаблонов с (потенциально выведенными) аргументами шаблонов, заменяемых соответствующими параметрами шаблона. Если возникает ошибка во время замены набора аргументов для любого данного шаблона, компилятор удаляет потенциальную перегрузку из набора кандидатов вместо того, чтобы останавливаться с ошибкой компиляции, при условии, что стандарт C ++ позволяет отбросить ошибку замены, как упомянуто. [ 2 ] Если один или несколько кандидатов остаются, и разрешение перегрузки преуспевает, вызов хорошо сформирован.

Следующий пример иллюстрирует основной экземпляр Sfinae:

struct Test {
  typedef int foo;
};

template <typename T>
void f(typename T::foo) {}  // Definition #1

template <typename T>
void f(T) {}  // Definition #2

int main() {
  f<Test>(10);  // Call #1.
  f<int>(10);   // Call #2. Without error (even though there is no int::foo)
                // thanks to SFINAE.
  return 0;
}

Здесь попытка использовать не класс типа в квалифицированном имени ( T::foo) приводит к вычтению сбоя для f<int> потому что int не имеет вложенного типа названного foo, но программа хорошо сформирована, потому что в наборе функций кандидатов остается действительная функция.

Несмотря на то, что Sfinae был первоначально введен во избежание создания плохо сформированных программ, когда были видны неродственные декларации шаблонов (например, через включение файла заголовка), многие разработчики позже обнаружили, что поведение полезно для самоанализа времени компиляции. В частности, он позволяет шаблону определять определенные свойства своих шаблонных аргументов во время экземпляра.

Например, Sfinae можно использовать для определения того, содержит ли тип определенный Typedef:

#include <iostream>

template <typename T>
struct has_typedef_foobar {
  // Types "yes" and "no" are guaranteed to have different sizes,
  // specifically sizeof(yes) == 1 and sizeof(no) == 2.
  typedef char yes[1];
  typedef char no[2];

  template <typename C>
  static yes& test(typename C::foobar*);

  template <typename>
  static no& test(...);

  // If the "sizeof" of the result of calling test<T>(nullptr) is equal to
  // sizeof(yes), the first overload worked and T has a nested type named
  // foobar.
  static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
};

struct foo {
  typedef float foobar;
};

int main() {
  std::cout << std::boolalpha;
  std::cout << has_typedef_foobar<int>::value << std::endl;  // Prints false
  std::cout << has_typedef_foobar<foo>::value << std::endl;  // Prints true
  return 0;
}

Когда T имеет вложенный тип foobar определено, экземпляр первого test Работы и константа нулевого указателя успешно прошли. (И полученный тип выражения yes.) Если он не работает, единственная доступная функция - вторая testи полученный тип выражения noПолем Ellipsis используется не только потому, что он примет любой аргумент, но и потому, что его ранг преобразования является самым низким, поэтому вызов первой функции будет предпочтительным, если это возможно; Это устраняет двусмысленность.

C ++ 11 Упрощение

[ редактировать ]

В C ++ 11 приведенный выше код может быть упрощен до:

#include <iostream>
#include <type_traits>

template <typename... Ts>
using void_t = void;

template <typename T, typename = void>
struct has_typedef_foobar : std::false_type {};

template <typename T>
struct has_typedef_foobar<T, void_t<typename T::foobar>> : std::true_type {};

struct foo {
  using foobar = float;
};

int main() {
  std::cout << std::boolalpha;
  std::cout << has_typedef_foobar<int>::value << std::endl;
  std::cout << has_typedef_foobar<foo>::value << std::endl;
  return 0;
}

При стандартизации идиомы обнаружения в библиотеке Fundamental V2 (N4562) приведенный выше код может быть переписан следующим образом:

#include <iostream>
#include <type_traits>

template <typename T>
using has_typedef_foobar_t = typename T::foobar;

struct foo {
  using foobar = float;
};

int main() {
  std::cout << std::boolalpha;
  std::cout << std::is_detected<has_typedef_foobar_t, int>::value << std::endl;
  std::cout << std::is_detected<has_typedef_foobar_t, foo>::value << std::endl;
  return 0;
}

Разработчики Boost использовали Sfinae в Boost :: enable_if [ 3 ] и другими способами.

  1. ^ Видес, Дэвид; Николай М. Джосуттис (2002). Шаблоны C ++: Полное руководство . Аддисон-Уэсли Профессионал. ISBN  0-201-73484-2 .
  2. ^ Международная организация по стандартизации. «ISO/IEC 14882: 2003, языки программирования - C ++», § 14.8.2.
  3. ^ Увеличить включение, если
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: e5f17ab5bbbd9dfbbc7ba1e82a2eec83__1722754380
URL1:https://arc.ask3.ru/arc/aa/e5/83/e5f17ab5bbbd9dfbbc7ba1e82a2eec83.html
Заголовок, (Title) документа по адресу, URL1:
Substitution failure is not an error - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)