Nie potrafię jednoznacznie zrozumieć, co to znaczy, gdy ktoś wspomina, że dana funkcja, struktura lub ... jest przyjazny dla SFINAE.Co to znaczy, gdy ktoś mówi, że coś jest przyjazne SFINAE?
Czy ktoś mógłby to wyjaśnić?
Nie potrafię jednoznacznie zrozumieć, co to znaczy, gdy ktoś wspomina, że dana funkcja, struktura lub ... jest przyjazny dla SFINAE.Co to znaczy, gdy ktoś mówi, że coś jest przyjazne SFINAE?
Czy ktoś mógłby to wyjaśnić?
Kiedy pozwala na awarię podstawienia bez twardego błędu (jak static_assert
).
np
template <typename T>
void call_f(const T& t)
{
t.f();
}
Funkcja jest zgłaszana do wszystkich T
, nawet tych z nie mają f
, więc nie można zrobić SFINAE na call_f<WithoutF>
jako metoda istnieje. (Demo kodu, który nie jest kompilowany).
z następującymi zmianami:
template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
t.f();
}
Sposób istnieje tylko dla ważnego T. więc można użyć SFINAE jak
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);
}
Zanotować int = 0
i ...
jest zamówienie przeciążenia. Demo
-
Innym przypadkiem jest gdy szablon dodać specjalny parametr stosowania SFINAE dla specjalizacji:
template <typename T, typename Enabler = void> struct S;
A potem
// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};
Jednostka jest określany SFINAE- przyjazny, jeśli można go użyć w kontekście SFINAE, nie powodując poważnego błędu po niepowodzeniu substytucji. Zakładam, że już wiesz, czym jest SFINAE, ponieważ jest to zupełnie inne pytanie samo w sobie.
W kontekście standaryzacji C++ termin przyjazny dla SFINAE został dotychczas zastosowany do std::result_of
i std::common_type
. Weźmy następujący przykład:
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"));
}
Bez SFINAE przyjaznej common_type
, byłoby to nie skompilować, ponieważ std::common_type<std::string, int>::type
przyniosłoby twardy błąd podczas zastępowania szablon argumentów. Po wprowadzeniu przyjaznego dla SFINAE modelu common_type
(N3843) ten przykład staje się dobrze sformułowany, ponieważ std::common_type<std::string, int>::type
powoduje niepowodzenie substytucji, tak że przeciążenie jest wykluczone z realnego zestawu.
Oto podobny przykład z 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);
}
Bez SFINAE przyjazne result_of
, byłoby to nie skompilować, ponieważ std::result_of<int()>::type
przyniosłoby twardy błąd podczas zastępowania szablon argumentów. Po wprowadzeniu przyjaznego dla SFINAE result_of
(N3462) ten przykład staje się dobrze uformowany, ponieważ std::result_of<int()>::type
powoduje niepowodzenie substytucji, tak że przeciążenie jest wykluczone z realnego zestawu.
Czy 'int = 0' kontra' ... 'nie jest wieloznaczny? – TartanLlama
Co masz na myśli przez: * nie możesz zrobić SFINAE na 'call_f' *? –
@TartanLlama nie, nie dlatego, że 'int' jest bardziej wyspecjalizowany__ niż' ... – tkausl