Подтвердить что ты не робот

Что значит, когда кто-то говорит, что это SFINAE-дружественный?

Я не могу четко понять, что это означает, когда упоминается, что определенная функция, структура или... SFINAE-friendly.

Кто-нибудь, пожалуйста, объясните это?

4b9b3361

Ответ 1

Если он допускает сбой замены без жесткой ошибки (как static_assert).

например

template <typename T>
void call_f(const T& t)
{
    t.f();
}

Функция объявляется для всех T, даже те, у которых нет f, поэтому вы не можете делать SFINAE на call_f<WithoutF> по мере того, как этот метод существует. (Демо некомпилирующего кода).

Со следующим изменением:

template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
    t.f();
}

Метод существует только для действительного T. поэтому вы можете использовать SFINAE как

template<typename T>
auto call_f_if_available_impl(const T& t, int) -> decltype(call_f(t))
{
    call_f(t);
}

template<typename T>
auto call_f_if_available_impl(const T& t, ...)
{
    // Do nothing;
}

 template<typename T>
 auto call_f_if_available(const T& t)
 {
    call_f_if_available_impl(t, 0);
 }

Обратите внимание, что int = 0 и ... - это порядок перегрузки. Демо

-

Другой случай, когда шаблон добавляет специальный параметр для применения SFINAE для специализации:

template <typename T, typename Enabler = void> struct S;

И затем

// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};

Ответ 2

Сущность называется SFINAE-дружественной, если ее можно использовать в контексте SFINAE без возникновения жесткой ошибки при ошибке замены. Я предполагаю, что вы уже знаете, что такое SFINAE, поскольку это целый другой вопрос сам по себе.

В контексте стандартизации С++ термин SFINAE-friendly до сих пор применялся к std::result_of и std::common_type. Возьмем следующий пример:

template <typename T>
void foo(T x, typename std::common_type<T, int>::type y) {}

void foo(std::string x, std::string y) {}

int main()
{
    foo(std::string("hello"), std::string("world"));
}

Без SFINAE-дружественного common_type это не скомпилируется, потому что std::common_type<std::string, int>::type приведет к жесткой ошибке при замене аргумента шаблона. С введением SFINAE-дружественного common_type (N3843) этот пример становится хорошо сформированным, потому что std::common_type<std::string, int>::type производит сбой замены, поэтому что перегрузка исключена из жизнеспособного набора.

Здесь аналогичный пример с result_of:

template <typename T>
auto bar(T f) -> typename std::result_of<T()>::type { return f(); }

void bar(int n) {}

int main()
{
    bar(42);
}

Без SFINAE-дружественного result_of это не скомпилируется, потому что std::result_of<int()>::type приведет к жесткой ошибке при замене аргумента шаблона. С введением SFINAE-дружественного result_of (N3462) этот пример становится хорошо сформированным, потому что std::result_of<int()>::type производит сбой замены, поэтому что перегрузка исключена из жизнеспособного набора.