What is the "SFINAE expression"?

At http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx , the VC ++ team officially announces that it has not yet implemented the core C ++ 11 Expression SFINAE function. However, the following code examples copied from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html are accepted by the VC ++ compiler.

example 1:

template <int I> struct A {}; char xxx(int); char xxx(float); template <class T> A<sizeof(xxx((T)0))> f(T){} int main() { f(1); } 

Example 2:

 struct X {}; struct Y { Y(X){} }; template <class T> auto f(T t1, T t2) -> decltype(t1 + t2); // #1 X f(Y, Y); // #2 X x1, x2; X x3 = f(x1, x2); // deduction fails on #1 (cannot add X+X), calls #2 

My question is: what is the "SFINAE expression"?

+54
c ++ c ++ 11 visual-c ++ templates sfinae
Sep 29 '12 at 15:37
source share
1 answer

The SFINAE expression is explained quite well in the document you linked, I think. This is SFINAE in expressions. If the expression inside decltype invalid, ok, remove the function from the VIP congestion room. You can find the normative wording at the end of this answer.

Note on VC ++: they did not fully implement it. On simple expressions, this may work, but on others it will not. See the discussion in the comments in this answer for examples that fail. To make it simple, this will not work:

 #include <iostream> // catch-all case void test(...) { std::cout << "Couldn't call\n"; } // catch when C is a reference-to-class type and F is a member function pointer template<class C, class F> auto test(C c, F f) -> decltype((c.*f)(), void()) // 'C' is reference type { std::cout << "Could call on reference\n"; } // catch when C is a pointer-to-class type and F is a member function pointer template<class C, class F> auto test(C c, F f) -> decltype((c->*f)(), void()) // 'C' is pointer type { std::cout << "Could call on pointer\n"; } struct X{ void f(){} }; int main(){ X x; test(x, &X::f); test(&x, &X::f); test(42, 1337); } 

Clang returns the expected value:

You can call with a link I can call with a pointer
Failed to call

With MSVC, I get ... well, a compiler error:

 1> src \ main.cpp (20): error C2995: '' unknown-type 'test (C, F)': function template has already been defined
 1> src \ main.cpp (11): see declaration of 'test'

It also seems that GCC 4.7.1 does not quite match the task:

 source.cpp: In substitution of 'template decltype ((c. * f (), void ())) test (C, F) [with C = X *;  F = void (X :: *) ()] ':
 source.cpp: 29: 17: required from here
 source.cpp: 11: 6: error: cannot apply member pointer 'f' to 'c', which is of non-class type 'X *'
 source.cpp: In substitution of 'template decltype ((c. * f (), void ())) test (C, F) [with C = int;  F = int] ':
 source.cpp: 30: 16: required from here
 source.cpp: 11: 6: error: 'f' cannot be used as a member pointer, since it is of type 'int'

The common use of the SFINAE expression is to define traits as a sign to check if a class supports a particular member function:

 struct has_member_begin_test{ template<class U> static auto test(U* p) -> decltype(p->begin(), std::true_type()); template<class> static auto test(...) -> std::false_type; }; template<class T> struct has_member_begin : decltype(has_member_begin_test::test<T>(0)) {}; 

Real-time example. (surprisingly, works again on GCC 4.7.1.)

See also this my answer , which uses the same technique in a different environment (aka without signs).




Normative wording:

Β§14.8.2 [temp.deduct]

p6 At certain points in the process of subtracting a template argument, it is necessary to take the type of function that uses the template parameters and replace these template parameters with the corresponding template arguments. This is done at the beginning of the output of the template argument, when any explicitly specified template arguments are substituted into the function type, and again at the end of the output of the template argument, when any template arguments that were derived or obtained from the default arguments are substituted .

p7 Substitution occurs in all types and expressions that are used in a function type and in template parameter declarations. Expressions include not only constant expressions , such as those that appear within the boundaries of an array or as arguments to a nontype pattern , but also general expressions (i.e. decltype expressions) inside sizeof , decltype and other contexts that allow non-constant expressions.

p8 If substitution results in an invalid type or expression, the deduction type fails. An invalid type or expression is one that would be poorly formed if it were written using substituted arguments. [...]

+65
Sep 29 '12 at 16:10
source share



All Articles