猿问

什么是“表达SFINAE”?

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


范例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

我的问题是:什么是“表达SFINAE”?


慕的地6264312
浏览 427回答 1
1回答

倚天杖

我认为,您所链接的论文中对SFINAE的表达进行了很好的解释。在表达式上是SFINAE。如果其中的表达式decltype无效,那么请从重载的VIP休息室中调用该函数。您可以在此答案的末尾找到规范性措词。对VC的注意事项++:他们没有实现它完全。在简单的表达式上,它可能会起作用,但在其他表达式上,它将不起作用。有关失败的示例,请参见此答案的注释中的讨论。为了简单起见,这是行不通的:#include <iostream>// catch-all casevoid test(...){&nbsp; std::cout << "Couldn't call\n";}// catch when C is a reference-to-class type and F is a member function pointertemplate<class C, class F>auto test(C c, F f) -> decltype((c.*f)(), void()) // 'C' is reference type{&nbsp; std::cout << "Could call on reference\n";}// catch when C is a pointer-to-class type and F is a member function pointertemplate<class C, class F>auto test(C c, F f) -> decltype((c->*f)(), void()) // 'C' is pointer type{&nbsp; std::cout << "Could call on pointer\n";}struct X{&nbsp; void f(){}};int main(){&nbsp; X x;&nbsp; test(x, &X::f);&nbsp; test(&x, &X::f);&nbsp; test(42, 1337);}对于Clang,这将输出预期的结果:可以用引用调用可以用指针调用不能调用使用MSVC,我得到...好吧,编译器错误:1> src \ main.cpp(20):错误C2995:“未知类型” test(C,F)':功能模板已经定义1> src \ main.cpp(11):参见'test'的声明似乎GCC 4.7.1还不能完全完成任务:source.cpp:代替'模板decltype((c。* f(),void()))test(C,F)[C = X *; F =无效(X :: *)()]':source.cpp:29:17:从这里需要source.cpp:11:6:错误:无法将成员指针'f'应用于非类类型'X *'的'c'source.cpp:代替'template decltype((c。* f(),void()))test(C,F)[C = int; F = int]':source.cpp:30:16:从这里需要source.cpp:11:6:错误:'f'不能用作成员指针,因为它的类型为'int'表达式SFINAE的常见用法是在定义特征时,例如用于检查类是否具有某个成员函数的特征:struct has_member_begin_test{&nbsp; template<class U>&nbsp; static auto test(U* p) -> decltype(p->begin(), std::true_type());&nbsp; template<class>&nbsp; static auto test(...) -> std::false_type;};template<class T>struct has_member_begin&nbsp; : decltype(has_member_begin_test::test<T>(0)) {};现场示例。(令人惊讶的是,这再次适用于GCC 4.7.1。)另请参阅我的答案,该答案在另一种环境(也称为无特征)中使用相同的技术。规范用语:§14.8.2 [temp.deduct]p6 在模板自变量推导过程中的某些点,必须采用利用模板参数的函数类型,并用相应的模板自变量替换这些模板参数。当将任何显式指定的模板参数替换为函数类型时,此操作在模板参数推论的开始时进行;当替换从默认参数推论或获得的任何模板参数时,在模板参数推论的末尾再次进行。p7 替换发生在函数类型和模板参数声明中使用的所有类型和表达式中。表达式不仅包括常量表达式(例如出现在数组范围内或作为非类型模板参数的常量表达式),而且还包括,和内部 允许非常量表达式的其他通用表达式(即,非常量表达式)。sizeofdecltypep8如果替换导致无效的类型或表达式,则类型推导失败。无效的类型或表达式是使用替换参数编写的格式或表达式。[...]
随时随地看视频慕课网APP
我要回答