【问题标题】:Why does std::forward not work in the lambda body?为什么 std::forward 在 lambda 主体中不起作用?
【发布时间】:2022-01-09 18:18:45
【问题描述】:
#include <utility>

void f(auto const& fn1)
{
    {
        auto fn2 = std::forward<decltype(fn1)>(fn1);
        auto fn3 = std::forward<decltype(fn2)>(fn2); // ok
        fn3();
    }

    [fn2 = std::forward<decltype(fn1)>(fn1)]
    {
        auto const fn3 = fn2;
        auto fn4 = std::forward<decltype(fn3)>(fn3); // ok
        fn4();
    
        auto fn5 = std::forward<decltype(fn2)>(fn2); // error
        fn5();
    }();
}

int main()
{
    f([] {});
}

godbolt demo

为什么 std::forward 在 lambda 主体中不起作用?


更新信息:

g++ 可以,但是 clang++ 拒绝它。谁是正确的?

【问题讨论】:

  • 为什么你不把它写成一个没有 auto 参数的“普通”模板。在你的情况下,所有 decltype 的东西都让我作为一个读者很困惑。拥有简单的typename T 会更容易理解。而且我也很难理解为什么使用 const& 因为它不是转发引用而是使用 std::forward。
  • 这是一个最小化的POC。

标签: c++ lambda c++20 mutable perfect-forwarding


【解决方案1】:

Clang 拒绝它是正确的。

decltype(fn2) 给出 fn2 的类型,假设 lambda 闭包类型是 T,那么它将是 T。 lambda 的函数调用运算符是 const 限定的,那么 std::forward&lt;decltype(fn2)&gt;(fn2) 调用失败。 std::forward 的模板参数明确指定为T,然后std::forward&lt;decltype(fn2)&gt; 应该接受T&amp;(和T&amp;&amp;)作为其参数类型,但const fn2 不能被绑定引用非常量

作为解决方法,您可以将 lambda 标记为 mutable

[fn2 = std::forward<decltype(fn1)>(fn1)] mutable
{
    auto fn3 = std::forward<decltype(fn2)>(fn2); // fine
    fn3();
}();

【讨论】:

  • 但是fn2 是左值。它是如何绑定到T&amp;&amp;的?
  • @TheScore 抱歉,我忘了提到采用左值引用的重载。
  • 谢谢你的编辑完美地回答了我的疑问。
【解决方案2】:

lambda 的捕获是闭包类的成员,主体是operator() const

您正试图在 const 成员函数中移动类的数据成员,这是编译器错误告诉您的内容

note: candidate function template not viable: 1st argument ('const (lambda at <source>:20:7)') would lose const qualifier

【讨论】:

  • 我的意图是复制,而不是移动,fn2fn3,为什么 std::forward&lt;decltype(fn2)&gt;(fn2) 不是 T const&amp; 在 lambda 正文中?
  • @xmllmx 因为它是一个值捕获,而不是一个引用捕获
  • 我还有问题,请参阅我更新的问题。
  • 我认为转发一个 const 对象应该产生T const&amp; 而不是T&amp;&amp;
  • @xmllmx 它是 const 上下文中的可变对象
猜你喜欢
  • 1970-01-01
  • 2017-11-05
  • 2011-02-27
  • 2014-12-20
  • 1970-01-01
  • 2019-04-14
  • 2018-08-20
  • 2014-06-12
  • 2016-03-04
相关资源
最近更新 更多