decltype(auto) deduced return type from lambda capture

谁说胖子不能爱 提交于 2019-12-21 09:03:43

问题


I have compilers disagreeing on a small C++14 code snippet:

#include <cassert>

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

int main()
{
  unmovable u;

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

  assert(&uu == &u);
}

The program is accepted by g++4.9.3, g++-5.1.0, g++-5.2.0 and VisualStudio 2015, but not by clang++-3.7.

clang++-3.7 deduces the return type to be unmovable (value) and not unmovable&.

If the program is changed slightly, so that the variable u is global, then all compilers agree on the error.

As I understand it, the captured u in the lambda should be of type unmovable& when the variable is local.

I don't have the C++14 standard, but hopefully the draft from github is relevant. My interpretation of 7.1.6.2 and 7.1.6.4 is that decltype(auto) becomes decltype(u) from the return, which in the global case should be unmovable (value) and in the lambda reference capture of the local u, it should become unmovable& since the captured variable must be of type unmovable&. This would indicate that clang++ got it wrong.

If I change the lambda and its use slightly:

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

then all compilers accept it, regardless of whether u is global or local, which I think strengthens my interpretation of the decltype(auto) deduction, since v here definitely becomes of type unmovable&.

Is my interpretation correct and thus clang++ incorrect?


回答1:


clang seems correct to me. I agree with your interpretation that the lambda return type must be decltype(u), but not that decltype(u) is unmovable&.

5.1.2 Lambda expressions [expr.prim.lambda]

18 Every id-expression within the compound-statement of a lambda-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. Furthermore, such an id-expression does not cause the implicit capture of the entity. -- end note ] [...]

19 Every occurrence of decltype((x)) where [...]

p19 doesn't apply, since you have decltype(u), not decltype((u)).

p18 then says that as the u in decltype(u) is not an odr-use, it refers to the original entity, it does not get transformed to an access of the member of the closure type.

However, p19 does make it clear that if you write your return statement as

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

then the lambda will return u by reference. This will work with clang, if this is the behaviour you were after.



来源:https://stackoverflow.com/questions/33854388/decltypeauto-deduced-return-type-from-lambda-capture

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!