【问题标题】:Why does decltype(auto) not work as expected?为什么 decltype(auto) 不能按预期工作?
【发布时间】:2018-12-11 05:30:06
【问题描述】:
#include <type_traits>
#include <utility>

int main()
{
    auto f1 = [](auto&& e) -> auto
    {
        return e;
    };

    auto f2 = [](auto&& e) -> auto&
    {
        return e;
    };

    auto f3 = [](auto&& e) -> auto&&
    {
        return e;
    };

    auto f4 = [](auto&& e) -> decltype(auto)
    {
        return e;
    };

    int n{};

    f1(std::move(n)); // ok
    f2(std::move(n)); // ok
    f3(std::move(n)); // ok
    f4(std::move(n)); // error
}

clang 的错误信息:

错误:对“int”类型的右值引用无法绑定到“int”类型的左值

对我来说,decltype(auto) 只有三种可能的推导类型:

  1. auto
  2. auto&amp;
  3. auto&amp;&amp;

为什么f4 出错而其他三个都正常?

【问题讨论】:

  • 该错误来自 Clang。 GCC 似乎接受了它。我猜这是一个 Clang 错误。
  • decltype(auto)的返回类型表示return e;导致返回类型为decltype(e),即int&amp;&amp;对应f4
  • @M.M 为什么f3 可以,而f4 不行?
  • @xmllmx auto&amp;&amp;f3(std::move(n))调用的实例化中推导出int&amp;e可以初始化int&amp;

标签: c++ lambda c++14 decltype type-deduction


【解决方案1】:

这是GCC bug

decltype(auto) = e 等价于decltype(e) 并产生e 的声明类型。

auto 用作模板参数,这意味着auto&amp;&amp; 与发明模板参数的T&amp;&amp;(转发引用)相同。

对于f1,返回类型推导出为int

对于f2,返回类型auto&amp; 等价于T&amp;,推导出T=int 是左值e 的类型,这里你将int&amp; 绑定到@ 987654336@.

对于 f3,请考虑:

auto&& t = n;
static_assert(std::is_same_v<decltype(t), int&>); // true

对于f3 的返回,auto&amp;&amp; 等价于发明的模板参数T&amp;&amp;,它是一个转发引用,它用左值初始化,产生T&amp; 推导出T=int,然后再次。 .. 将int&amp; 绑定到左值e

现在对于 f4 考虑一下:

int&& r = 9;
static_assert(std::is_same_v<decltype(r), int&&>); // true (1)

decltype(auto) t = r; // fail with the same error you got.

f4 的参数也是一个转发引用T&amp;&amp;,它使用 xvalue std::move(n) 进行初始化,由此推导出T=int 得到一个参数int&amp;&amp; e。一个返回类型为decltype(auto)return e 表示实际返回的是decltype(e),那么如你所见(1) 为真,decltype(e) 同样成立,这意味着f4 的实际返回是int&amp;&amp; ...问题就来了,f4 试图将右值int&amp;&amp; 绑定到左值e,这是被禁止的。

您还可以查看@StoryTeller's answer 了解 GCC 错误。

【讨论】:

  • 应该auto&amp;&amp; t = n;auto&amp;&amp; t = std::move(n); 吗?
  • 这取决于你想做什么......你应该把这些想象成你正在使用像this这样的函数模板
  • f3int&amp;int&amp;&amp;的推导返回类型是什么?
  • @xmllmx int&amp; 你可以用static_assert(std::is_same_v&lt;int&amp;, decltype(f3(std::move(n)))&gt;);检查它
  • @xmllmx 很高兴我能帮上忙
猜你喜欢
  • 1970-01-01
  • 2021-05-30
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多