我有兴趣了解一下,尾部的 auto&&
返回型是指,具体来说,与 decltype(auto)
在这里是不行的,还有一个未指定的返回类型,也是不行的。
在下面的代码中。fn
返回 x_
参数的字段。当参数是一个l值时。x_
返回为一个l值,等等。
的例子中。fn_bad[123]
,它似乎返回 int
即使提供了lvalue参数,也是如此。我知道为什么 -> 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
}
但我以为->
decltype(auto)
会返回int&
这是预期的行为 decltype
,
(重点是我)
检查实体的声明类型 或 表达式的类型和值类别。
1) 如果参数是一个未加括号的id表达式或一个 未括号的类成员访问表达式,那么decltype就会产生这个表达式所命名的实体的类型。
所以这个表达式的结果是 decltype(auto)
关于 std::forward<decltype(foo)>(foo).x_
产生数据成员的类型 x_
即: int
.
如果你加上括号,如
[](auto&& foo) -> decltype(auto) { return (std::forward<decltype(foo)>(foo).x_); };
// ^ ^
然后
2)如果参数是其他任何类型的表达式
T
和a) 如果 表情 是x值,那么
decltype
产量T&&
b) 如果 表情 是l值,那么decltype
产量T&
c) 如果 表情 是prvalue,那么decltype
产量T
.请注意,如果一个对象的名称被括号括起来,它将被视为一个普通的l-value表达式,所以
decltype(x)
和decltype((x))
往往是不同的类型。
然后,正如你所说,当向lambda传递一个lvalue时,表达式为 (std::forward<decltype(foo)>(foo).x_)
是一个l值,那么返回的类型将是 int&
当传入一个rvalue的表达式是xvalue时,返回类型将是 int&&
(这可能会造成悬空引用的麻烦)。
对于第2种情况,根据一般的规则 模板引论每当传递lvalue或rvalue时,返回类型始终是 int
.
第3种情况与第2种情况相同。
对于第4种情况,特殊规则为 转发参考 应用,那么返回类型将是 int&
当返回表达式为lvalue时,以及 int&&
当返回表达式为rvalue时。