"Substitution Failure Is Not An Error"
This rule applies during overload resolution of function templates: When substituting the explicitly specified or deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error.
This feature is used in template metaprogramming.
Function template parameters are substituted (replaced by template arguments) twice:
Substitution occurs in.
| (since C++11) |
| (since C++20) |
A substitution failure is any situation when the type or expression above would be ill-formed (with a required diagnostic), if written using the substituted arguments.
Only the failures in the types and expressions in the immediate context of the function type or its template parameter types or its explicit specifier (since C++20) are SFINAE errors. If the evaluation of a substituted type/expression causes a side-effect such as instantiation of some template specialization, generation of an implicitly-defined member function, etc, errors in those side-effects are treated as hard errors. A lambda expression is not considered part of the immediate context. (since C++20).
Substitution proceeds in lexical order and stops when a failure is encountered. template <typename A> struct B { using type = typename A::type; }; template < class T, class = typename T::type, // SFINAE failure if T has no member type class U = typename B<T>::type // hard error if T has no member type // (guaranteed to not occur as of C++14) > void foo (int); If there are multiple declarations with different lexical orders (e.g. a function template declared with trailing return type, to be substituted after a parameter, and redeclared with ordinary return type that would be substituted before the parameter), then the program is ill-formed; no diagnostic required. | (since C++14) |
The following type errors are SFINAE errors:
| (since C++11) |
template <int I> void div(char(*)[I % 2 == 0] = 0) { // this overload is selected when I is even } template <int I> void div(char(*)[I % 2 == 1] = 0) { // this overload is selected when I is odd }
::
template <class T> int f(typename T::B*); template <class T> int f(T); int i = f<int>(0); // uses second overload
template <int I> struct X { }; template <template <class T> class> struct Z { }; template <class T> void f(typename T::Y*){} template <class T> void g(X<T::N>*){} template <class T> void h(Z<T::template TT>*){} struct A {}; struct B { int Y; }; struct C { typedef int N; }; struct D { typedef int TT; }; struct B1 { typedef int Y; }; struct C1 { static const int N = 0; }; struct D1 { template <typename T> struct TT { }; }; int main() { // Deduction fails in each of these cases: f<A>(0); // A does not contain a member Y f<B>(0); // The Y member of B is not a type g<C>(0); // The N member of C is not a non-type h<D>(0); // The TT member of D is not a template // Deduction succeeds in each of these cases: f<B1>(0); g<C1>(0); h<D1>(0); } // todo: needs to demonstrate overload resolution, not just failure
template<typename T> class is_class { typedef char yes[1]; typedef char no [2]; template<typename C> static yes& test(int C::*); // selected if C is a class type template<typename C> static no& test(...); // selected otherwise public: static bool const value = sizeof(test<T>(0)) == sizeof(yes); };
template <class T, T> struct S {}; template <class T> int f(S<T, T()>*); struct X {}; int i0 = f<X>(0); // todo: needs to demonstrate overload resolution, not just failure
template <class T, T*> int f(int); int i2 = f<int,1>(0); // can’t conv 1 to int* // todo: needs to demonstrate overload resolution, not just failure
| (until C++11) |
The following expression errors are SFINAE errors.
struct X {}; struct Y { Y(X){} }; // X is convertible to Y template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); // overload #1 X f(Y, Y); // overload #2 X x1, x2; X x3 = f(x1, x2); // deduction fails on #1 (expression x1+x2 is ill-formed) // only #2 is in the overload set, and is called | (since C++11) |
Only constant expressions that are used in types (such as array bounds) were required to be treated as SFINAE (and not hard errors) before C++11. | (until C++11) |
The standard library component std::enable_if
allows for creating a substitution failure in order to enable or disable particular overloads based on a condition evaluated at compile time.
The standard library component std::void_t
is another utility metafunction that simplifies SFINAE applications.
In addition, many type traits are implemented using SFINAE.
Where applicable, tag dispatch, static_assert, and, if available, concepts, are usually preferred over direct use of SFINAE.
A common idiom is to use expression SFINAE on the return type, where the expression uses the comma operator, whose left subexpression is the one that is being examined (cast to void to ensure the user-defined operator comma on the returned type is not selected), and the right subexpression has the type that the function is supposed to return.
#include <iostream> // this overload is always in the set of overloads // ellipsis parameter has the lowest ranking for overload resolution void test(...) { std::cout << "Catch-all overload called\n"; } // this overload is added to the set of overloads if // C is a reference-to-class type and F is a pointer to member function of C template <class C, class F> auto test(C c, F f) -> decltype((void)(c.*f)(), void()) { std::cout << "Reference overload called\n"; } // this overload is added to the set of overloads if // C is a pointer-to-class type and F is a pointer to member function of C template <class C, class F> auto test(C c, F f) -> decltype((void)((c->*f)()), void()) { std::cout << "Pointer overload called\n"; } struct X { void f() {} }; int main(){ X x; test( x, &X::f); test(&x, &X::f); test(42, 1337); }
Output:
Reference overload called Pointer overload called Catch-all overload called
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/language/sfinae