类型是如何从自动返回类型推导出来的

How is type deduced from auto return type?

本文关键字:返回类型 类型      更新时间:2023-10-16

这个答案的代码片段如下:

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

它真的可以编译和工作(至少在Ideone上是这样)。

那么,在这种情况下,类型是如何推导出来的呢?

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

decltype( bool( fun(v[0] ) ), void() )

我快速看了一眼,但它看起来并不有效。这种情况下ideone错了吗?


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

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

另一个例子:

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

和另一个

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;

它们在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);
}

即使删除了行f(v,ops);f模板函数的返回类型也会被计算为void。

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

分解它,

bool( fun(v[0] ) ), void()

由两个表达式组成;第一个

bool( fun(v[0] ) )

被评估1并丢弃,给整个表达式值

void()

其是CCD_ 4类型的值2

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

这里使用逗号运算符的原因是为了确保只有当第一个子表达式有效时,整个表达式才有效;这是因为它在SFINAE中被用于在第一个子表达式无效的情况下将其从替换考虑中排除。

这是因为尽管decltype在语法上看起来像一个函数,但它实际上是一个语言构造,(像sizeof一样)被定义为接受单个参数。插入逗号运算符参数可能更清楚:

decltype( ( bool( fun(v[0] ) ), void() ) )

备注

  1. 表达式bool( fun(v[0] ) )实际上并没有被求值,因为我们处于一个未求值的上下文中(decltype,类似于sizeof)。这里重要的是,如果表达式作为一个整体进行了求值,则它将被求值,因此,如果子表达式无效,则整个表达式无效
  2. void()并不是真正的值,但它的行为类似于逗号运算符和decltype上下文中的值

decltype在括号之间生成表达式的类型,而不实际对其求值(在接下来的部分中请记住这一点)。

,运算符计算左边的参数/表达式,丢弃结果,计算右边的参数,然后得出结果。因此,返回类型变为void

对于bool(fun(v[0]))部分,这相当容易。CCD_ 18根据调用CCD_。如果f的返回类型不能转换为bool,这将触发一个错误,由于在decltype内部,这将导致SFINAE(这被称为"表达式SFINAE")。

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

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