为了账号安全,请及时绑定邮箱和手机立即绑定

什么是“表达SFINAE”?

什么是“表达SFINAE”?

C++
慕的地6264312 2019-10-09 15:27:55
在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); // #1X f(Y, Y);  // #2X x1, x2;X x3 = f(x1, x2);  // deduction fails on #1 (cannot add X+X), calls #2我的问题是:什么是“表达SFINAE”?
查看完整描述

1 回答

?
倚天杖

TA贡献1828条经验 获得超3个赞

我认为,您所链接的论文中对SFINAE的表达进行了很好的解释。在表达式上是SFINAE。如果其中的表达式decltype无效,那么请从重载的VIP休息室中调用该函数。您可以在此答案的末尾找到规范性措词。


对VC的注意事项++:他们没有实现它完全。在简单的表达式上,它可能会起作用,但在其他表达式上,它将不起作用。有关失败的示例,请参见此答案的注释中的讨论。为了简单起见,这是行不通的:


#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,这将输出预期的结果:


可以用引用

调用可以用指针

调用不能调用


使用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{

  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 在模板自变量推导过程中的某些点,必须采用利用模板参数的函数类型,并用相应的模板自变量替换这些模板参数。当将任何显式指定的模板参数替换为函数类型时,此操作在模板参数推论的开始时进行;当替换从默认参数推论或获得的任何模板参数时,在模板参数推论的末尾再次进行。


p7 替换发生在函数类型和模板参数声明中使用的所有类型和表达式中。表达式不仅包括常量表达式(例如出现在数组范围内或作为非类型模板参数的常量表达式),而且还包括,和内部 允许非常量表达式的其他通用表达式(即,非常量表达式)。sizeofdecltype


p8如果替换导致无效的类型或表达式,则类型推导失败。无效的类型或表达式是使用替换参数编写的格式或表达式。[...]


查看完整回答
反对 回复 2019-10-09
  • 1 回答
  • 0 关注
  • 426 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信