如何从自动退货类型中推断出类型?

BЈо*_*вић 8 c++ decltype c++11

这个答案有一个这样的代码片段:

template<class T, class F>
auto f(std::vector<T> v, F fun)
    -> decltype( bool( fun(v[0] ) ), void() )
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)

它真正编译和工作(至少在Ideone上).

那么,在这种情况下如何推断出类型?

c ++ 11标准真的允许下一行吗?

decltype( bool( fun(v[0] ) ), void() )
Run Code Online (Sandbox Code Playgroud)

我快速浏览了一下,看起来并不合适.在这种情况下,意识错误吗?


c ++ 11标准中的所有示例都是这样的,它们在decltype中只有一种类型:

struct A {
  char g();
  template<class T> auto f(T t) -> decltype(t + g())
  { return t + g(); }
};
Run Code Online (Sandbox Code Playgroud)

另一个例子 :

void f3() {
  float x, &r = x;
  [=] {
  decltype(x) y1;
  decltype((x)) y2 = y1;
  decltype(r) r1 = y1;
  decltype((r)) r2 = y2;
};
Run Code Online (Sandbox Code Playgroud)

和另一个

const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = i;
decltype(i) x2;
decltype(a->x) x3;
decltype((a->x)) x4 = x3;
Run Code Online (Sandbox Code Playgroud)

它们在decltype中只有一个参数.为什么顶级代码采用两个参数(用逗号分隔)?


我创建了另一个例子(无法编译):

#include <vector>
#include <iostream>

template<class T, class F>
auto f(std::vector<T> v, F fun) -> decltype(bool(fun(v[0])), void())
{
  // ...
  (void)v;(void)fun;

  return fun(v.size());
}

void ops(int)
{
}

int main(){
  std::vector<int> v;
  f(v, [](int){ return true; });
  f(v,ops);
}
Run Code Online (Sandbox Code Playgroud)

即使f(v,ops);删除了该行,f模板函数的返回类型也会被评估为void.

eca*_*mur 14

decltype( bool( fun(v[0] ) ), void() )使用逗号运算符.

打破它,

bool( fun(v[0] ) ), void()
Run Code Online (Sandbox Code Playgroud)

由两个表达式组成; 首先

bool( fun(v[0] ) )
Run Code Online (Sandbox Code Playgroud)

被评估为1并被丢弃,给出整体表达式的值

void()
Run Code Online (Sandbox Code Playgroud)

这是类型的值2void.

decltype然后产生表达式的类型,如上所述void.

这里使用逗号运算符的原因是为了确保整个表达式仅在第一个子表达式有效时才有效.这是因为如果第一个子表达式无效,它将在SFINAE中用于将其排除在替代考虑范围之外.

这是有效的,因为虽然decltype在语法上看起来像一个函数,但它实际上是一个语言结构,(like sizeof)被定义为采用单个参数.将逗号运算符参数括起来可能更清楚:

decltype( ( bool( fun(v[0] ) ), void() ) )
Run Code Online (Sandbox Code Playgroud)

笔记

  1. 表达式实际上bool( fun(v[0] ) )没有评估,因为我们处于非评估的上下文中(decltype类似于sizeof).这里的问题是,它如果表达式作为一个整体进行了评估,评估,这样,如果子表达式是无效的,那么整个表达式是无效的.
  2. void()实际上不是一个值,但它的行为类似于逗号运算符和/的上下文中的值decltype.

  • 我称之为"decltype"和"sizeof"执行"e-type-uations"的"评估":) (2认同)

Xeo*_*Xeo 7

decltype产生括号之间的表达式类型,而不实际评估它(请记住下一部分).

,运算符计算左边参数/表达,投结果远,评估右参数,导致产率.因此,返回类型变为void.

对于这bool(fun(v[0]))部分,它相当容易.bool(f(...))从调用的结果中构造一个临时的bool f.如果返回类型f不可转换为bool,则会触发错误,这将导致SFINAE位于内部decltype(这称为"表达式SFINAE").

f(v[0])将传递v[0]to 的返回值f,类型为T&.如果f没有T&可转换的参数,或者接受更多/更少的参数,则会触发错误,并且再次导致SFINAE的原因与上述相同.

(如果std::vector不支持也会发生同样的情况operator[].)