来自 C++ lambda 的 auto&& 返回类型

E_G*_*E_G 3 c++ decltype auto c++11 c++14

我很想了解尾随auto&&返回类型究竟是什么意思,特别是区别于decltype(auto),在这里不起作用,以及未指定的返回类型,它也不起作用。

在下面的代码中,fn返回x_参数的字段。当参数是左值时,x_作为左值返回,等等。

在 的示例中fn_bad[123]int即使提供了左值参数,它似乎也会返回。我可以理解为什么-> auto会导致这种情况,但我希望-> decltype(auto)返回int&。为什么只-> auto&&工作?

#include <utility>

struct Foo { int x_; };

int main() {
  auto fn_bad1 = [](auto&& foo) -> decltype(auto) { return std::forward<decltype(foo)>(foo).x_; };
  auto fn_bad2 = [](auto&& foo) -> auto           { return std::forward<decltype(foo)>(foo).x_; };
  auto fn_bad3 = [](auto&& foo)                   { return std::forward<decltype(foo)>(foo).x_; };
  auto fn      = [](auto&& foo) -> auto&&         { return std::forward<decltype(foo)>(foo).x_; };
  Foo a{};
  fn(a) = fn(Foo{100}); // doesn't compile with bad1, bad2, bad3
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 5

但我希望 ->decltype(auto)返回int&

这是 的预期行为decltype

(强调我的)

检查实体的声明类型表达式的类型和值类别。

1) 如果参数是无括号的 id-expression 或无括号的类成员访问表达式,则 decltype 产生由此表达式命名的实体的类型。

所以decltype(auto)on的结果是std::forward<decltype(foo)>(foo).x_数据成员的类型x_,即int

如果您将括号添加为

[](auto&& foo) -> decltype(auto) { return (std::forward<decltype(foo)>(foo).x_); };
//                                        ^                                   ^
Run Code Online (Sandbox Code Playgroud)

然后

2) 如果参数是任何其他类型的表达式T,并且

a) 如果表达式的值类别是 xvalue,则decltypeyield T&&
b) 如果表达式的值类别是左值,则decltype产生T&
c) 如果表达式的值类别是纯右值,则decltype产生T

请注意,如果一个对象的名称被加括号,它是作为一个普通的左值表达式处理,从而decltype(x)decltype((x))通常不同的类型。

然后,正如您所说,当将左值传递给 lambda 时,表达式(std::forward<decltype(foo)>(foo).x_)是一个左值,那么返回类型将是int&; 当传递一个右值时,表达式是一个 xvalue,然后返回类型将是int&&(这可能会导致悬空引用问题)。

对于第二种情况,根据模板参数推导的正常规则,每当传递左值或右值时,返回类型始终为int

第 3 种情况与第 2 种情况相同。

对于第 4 种情况,应用了转发引用的特殊规则,那么返回类型将是int&当返回表达式为左值时,int&&当返回表达式为右值时。

  • @E_G 这就是 `decltype` 的工作原理,是的,它很令人困惑,因为它提供了两个独立的功能。 (2认同)