3

我有兴趣了解尾随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
}
4

1 回答 1

5

但我预计 ->decltype(auto)会返回int&

这是 的预期行为decltype

(强调我的)

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

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

因此decltype(auto)on的结果std::forward<decltype(foo)>(foo).x_产生数据成员的类型x_,即int

如果将括号添加为

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

然后

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

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

请注意,如果对象的名称带有括号,则它被视为普通的左值表达式,因此decltype(x)通常decltype((x))是不同的类型。

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

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

第三种情况与第二种情况相同。

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

于 2020-05-12T01:19:33.233 回答