什么是“表达SFINAE”? [英] What is "Expression SFINAE"?

查看:269
本文介绍了什么是“表达SFINAE”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

At http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx, the VC++ team officially declare that they have not yet implemented the C++11 core feature "Expression SFINAE". 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.

示例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表达式?

推荐答案

链接,我想。它是表达式的 SFINAE 。如果 decltype 中的表达式无效,那么从VIP休息室中重载函数。你可以在这个答案的末尾找到规范的措辞。

Expression SFINAE is explained quite well in the paper you linked, I think. It's SFINAE on expressions. If the expression inside decltype isn't valid, well, kick the function from the VIP lounge of overloads. You can find the normative wording at the end of this answer.

关于VC ++的说明:他们没有完全实现。对于简单的表达式,它可能工作,但在别人,它不会。请参阅关于此答案的评论中的讨论,了解失败的示例。为了简单,这将不工作:

A note on VC++: They didn't implement it completely. On simple expressions, it might work, but on others, it won't. See a discussion in the comments on this answer for examples that fail. To make it simple, this won't work:

#include <iostream>

struct not_a_type{};

// 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,输出预期:

With Clang, this outputs the expected:


可以使用引用调用

可以使用指针调用

无法调用

Could call with reference
Could call with pointer
Couldn't call

有了MSVC,我得到...好了,编译器错误:

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'

看起来GCC 4.7.1还不足以完成任务:

It also seems that GCC 4.7.1 isn't quite up to 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'

表达式SFINAE的常见用法是定义traits时,如检查类是否运行某个成员函数:

A common use of Expression SFINAE is when defining traits, like a trait to check if a class sports a certain 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)) {};

Live example。

Live example. (Which, surprisingly, works again on GCC 4.7.1.)

另请参阅这个答案我在另一个环境(也没有性状)使用相同的技术。

See also this answer of mine, which uses the same technique in another environment (aka without traits).

规范性措词:

§14.8.2[temp.deduct]


p6 在模板参数扣除过程中的某些点,有必要采用一个使用模板参数的函数类型,并将这些模板参数替换为。当任何明确指定的模板参数被替换为函数类型时,这将在模板参数推导开始时完成,并且在模板参数末尾再次推导出任何模板参数时的

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

p7 替换出现在所有类型和表达式中,用于函数类型和模板参数声明。 表达式不仅包含常量表达式,例如出现在数组边界或非类型模板参数,还包括一般表达式(即非常量表达式) inside sizeof decltype 和允许非常量表达式的其他上下文。

p7 The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions.

p8如果替换导致无效的类型或表达式,则类型扣除失败。无效的类型或表达式是如果使用替换参数写入将是不成形的。 [...]

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

这篇关于什么是“表达SFINAE”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆