什么是“expressionSFINAE”?

在http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx,VC ++团队正式声明他们还没有实现C ++ 11核心function“Expression SFINAE”。 但是,从http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html复制的以下代码示例已被VC ++编译器接受。

例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); } 

例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 

我的问题是:什么是“expressionSFINAE”?

expression式SFINAE在你连接的文件中解释得很好,我想。 这是expression式上的SFINAE 。 如果decltype里面的expression式是无效的,那么从超载的VIPrest室踢出function。 你可以在这个答案的末尾find规范的措词。

关于VC ++的说明:他们没有完全实现。 在简单的expression式上,它可能会起作用,但是在其他情况下,它不会。 有关失败的示例,请参阅有关此答案的评论中的讨论。 为了简单起见,这是行不通的:

 #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); } 

与铿锵,这输出的预期:

可以打电话参考
可以用指针调用
不能打电话

使用MSVC,我得到了…一个编译器错误:

 1> src \ main.cpp(20):error C2995:''unknown-type'test(C,F)':function template has already defined
 1> src \ main.cpp(11):参见'test'声明

GCC 4.7.1似乎还不能完全胜任:

 source.cpp:代替'template decltype((c。* f(),void()))test(C,F)[with C = X *  F = void(X :: *)()]':
 source.cpp:29:17:从这里需要
 source.cpp:11:6:错误:无法将成员指针“f”应用于“c”,它是非types的“X *”
 source.cpp:代替'template decltype((c。* f(),void()))test(C,F)[with C = int;  F = int]':
 source.cpp:30:16:从这里需要
 source.cpp:11:6:错误:'f'不能用作成员指针,因为它的types是'int'

expression式SFINAE的一个常见用法是在定义特征时,比如特征来检查一个类是否运动某个成员函数:

 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)) {}; 

现场示例。 (令人惊讶的是,它再次在GCC 4.7.1上工作。)

另请参阅我的这个答案 ,它在另一个环境中使用相同的技术(又名没有特性)。


规范措辞:

§14.8.2 [temp.deduct]

p6 在模板参数演绎过程中的某些点上,需要使用一个函数types来使用模板参数,并将这些模板参数replace为相应的模板参数。 这是在模板参数推导开始时完成的,当任何明确指定的模板参数被replace为函数types时,并且在模板参数推导结束时,当从默认参数中推导出或获得的任何模板参数被replace时

p7 replace发生在函数types和模板参数声明中使用的所有types和expression式中。 这些expression式不仅包含常量expression式,例如出现在数组边界中的常量expression式或非types模板参数,还包括sizeofdecltype和允许非常量expression式的其他上下文中的常规expression式 (即非常量expression式)。

p8如果replace导致无效types或expression式,则键入扣减失败。 无效的types或expression式是使用replace参数编写的格式不正确的types或expression式。 […]