Non riesco a capire chiaramente cosa significa quando si menziona che una particolare funzione, struct o ... è compatibile con SFINAE.Che cosa significa quando uno dice qualcosa è amichevole con SFINAE?
Qualcuno potrebbe spiegarlo?
Non riesco a capire chiaramente cosa significa quando si menziona che una particolare funzione, struct o ... è compatibile con SFINAE.Che cosa significa quando uno dice qualcosa è amichevole con SFINAE?
Qualcuno potrebbe spiegarlo?
Quando consente la sostituzione senza errori (come static_assert
).
ad esempio
template <typename T>
void call_f(const T& t)
{
t.f();
}
La funzione è dichiarata per tutti T
, anche quelli con non hanno f
, quindi non si può fare SFINAE sul call_f<WithoutF>
come metodo esiste. (Demo di codice non compilato).
Con seguente modifica:
template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
t.f();
}
Il metodo esiste solo per valida T. in modo da poter utilizzare come 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);
}
Annotare il int = 0
e ...
è quello di ordinare il sovraccarico. Demo
-
Un altro caso è quando il modello aggiunge parametro speciale da applicare SFINAE di specializzazione:
template <typename T, typename Enabler = void> struct S;
E poi
// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};
Un'entità viene definito SFINAE- amichevole se può essere utilizzato nel contesto di SFINAE senza produrre un errore grave in caso di fallimento della sostituzione. Presumo che tu sappia già cos'è la SFINAE, poiché è un'intera altra questione in sé.
Nel contesto della standardizzazione C++, il termine SFINAE-friendly è stato finora applicato a std::result_of
e std::common_type
. Prendiamo il seguente esempio:
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"));
}
Senza SFINAE-friendly common_type
, questo non riuscirebbe a compilare, perché std::common_type<std::string, int>::type
produrrebbe un errore hardware durante la sostituzione del modello argomento. Con l'introduzione di SFINAE common_type
(N3843) questo esempio diventa ben formato, poiché std::common_type<std::string, int>::type
produce un errore di sostituzione in modo che il sovraccarico venga escluso dal set valido.
Ecco un esempio simile con 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);
}
Senza SFINAE-friendly result_of
, questo non riuscirebbe a compilare, perché std::result_of<int()>::type
produrrebbe un errore hardware durante la sostituzione del modello argomento. Con l'introduzione di SFINAE result_of
(N3462) questo esempio diventa ben formato, perché std::result_of<int()>::type
produce un errore di sostituzione in modo che il sovraccarico sia escluso dal set fattibile.
Non è 'int = 0' vs' ... 'ambiguo? – TartanLlama
Cosa intendi con: * non puoi fare SFINAE su 'call_f' *? –
@TartanLlama no non è perché 'int' è __more specializzato__ di' ... ' – tkausl