从lambda捕获推断出decltype(auto)返回类型

rol*_*ear 9 c++ lambda decltype c++11 c++14

我有编译器不同意一个小的C++ 14代码片段:

#include <cassert>

struct unmovable {
  unmovable() {}
  unmovable(unmovable&&) = delete;
};

int main()
{
  unmovable u;

  auto i = [&]() -> decltype(auto) { return u; };
  auto& uu = i();

  assert(&uu == &u);
}
Run Code Online (Sandbox Code Playgroud)

该程序被g ++ 4.9.3,g ++ - 5.1.0,g ++ - 5.2.0和VisualStudio 2015接受,但不是由clang ++ - 3.7接受.

clang ++ - 3.7推断返回类型为unmovable(值)而不是unmovable&.

如果程序稍微改变,以便变量u是全局的,那么所有编译器都会同意错误.

据我了解,当变量是本地变量时,ulambda中捕获的应该是类型unmovable&.

我没有C++ 14标准,但希望github的草案是相关的.我的7.1.6.2和7.1.6.4的解释是,decltype(auto)成为decltype(u)从返回,这在全球的情况下应该是unmovable(值),并在当地的拉姆达参考捕获u,它应该成为unmovable&自捕获的变量的类型必须为unmovable&.这表明clang ++错了.

如果我稍微更改lambda及其使用:

auto i = [](auto& v) -> decltype(auto) { return v; };
auto& uu = i(u);
Run Code Online (Sandbox Code Playgroud)

然后所有编译器都接受它,无论u是全局还是本地,我认为这加强了我对演绎的解释decltype(auto),因为v这里肯定会变成类型unmovable&.

我的解释是否正确,因此clang ++不正确?

小智 7

clang对我来说似乎是正确的.我同意你的解释,即在lambda返回类型必须是decltype(u),但不是说decltype(u)unmovable&.

5.1.2 Lambda表达式[expr.prim.lambda]

18 lambda 表达式复合语句中的每个id表达式都是由副本捕获的实体的odr-use(3.2)转换为对闭包类型的相应未命名数据成员的访问.[ 注意:不是odr-use 的id表达式是指原始实体,永远不是闭包类型的成员.此外,这样的id表达式不会导致实体的隐式捕获.- 尾注 ] [...]

19每次出现的decltype((x))地方[...]

p19不适用,因为你有decltype(u),不是decltype((u)).

p18然后说,因为uin decltype(u)不是odr-use,它指的是原始实体,它不会转换为闭包类型成员的访问.

但是,p19确实表明如果你把你的return陈述写成

auto i = [&]() -> decltype(auto) { return (u); };
Run Code Online (Sandbox Code Playgroud)

那么lambda将u通过引用返回.这将适用于clang,如果这是你所追求的行为.