Jump to content

Неудачная замена не является ошибкой

Ошибка замены не является ошибкой ( 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 можно использовать, чтобы определить, содержит ли тип определенное определение типа:

#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. Многоточие используется не только потому, что оно принимает любой аргумент, но и потому, что его ранг преобразования самый низкий, поэтому вызов первой функции будет предпочтительнее, если это возможно; это устраняет двусмысленность.

Упрощение С++ 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;
}

Благодаря стандартизации идиомы обнаружения в предложении Library 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
Номер скриншота №: e34d08a66c515fa65de55c3c1f577153__1702609680
URL1:https://arc.ask3.ru/arc/aa/e3/53/e34d08a66c515fa65de55c3c1f577153.html
Заголовок, (Title) документа по адресу, URL1:
Substitution failure is not an error - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)