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

Why does std::forward not work in the lambda body?

提问人:xmllmx 提问时间:12/3/2021 最后编辑:xmllmx 更新时间:12/3/2021 访问量:300

问:

#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 演示

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


更新信息:

g++ 没问题,但 clang++ 拒绝了它。谁是对的?

C++(英语:C++) λ C++20 可变 完美转发

评论

0赞 Klaus 12/3/2021
为什么不把它写成一个没有auto参数的“普通”模板。就你而言,所有 decltype 的东西都让我作为读者感到困惑。简单使它更容易理解。而且我还有一个问题,无法理解为什么你使用const&,因为它不是转发引用,而是使用std::forward。typename T
0赞 xmllmx 12/3/2021
这是一个最小化的 POC。

答:

5赞 Caleth 12/3/2021 #1

lambda 的捕获是闭包类的成员,正文是 。operator() const

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

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

评论

0赞 xmllmx 12/3/2021
我的意图是复制,而不是移动,到 ,为什么不在 lambda 正文中?fn2fn3std::forward<decltype(fn2)>(fn2)T const&
0赞 Caleth 12/3/2021
@xmllmx因为它是值捕获,而不是引用捕获
0赞 xmllmx 12/3/2021
我还有问题,请参阅我更新的问题。
0赞 xmllmx 12/3/2021
我认为转发一个常量对象应该产生而不是.T const&T&&
0赞 Caleth 12/3/2021
@xmllmx它是常量上下文中的可变对象
5赞 songyuanyao 12/3/2021 #2

叮叮当当拒绝它是正确的。

decltype(fn2)给出的类型是 ,假设 lambda 闭包类型是 ,那么它将是 。lambda 的函数调用运算符是 const 限定的,则无法调用。std::forward 的模板参数被显式指定,然后应该接受 (和 ) 作为其参数类型,但不能绑定到对 non-const 的引用。fn2TTstd::forward<decltype(fn2)>(fn2)Tstd::forward<decltype(fn2)>T&T&&constfn2

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

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

评论

2赞 TheScore 12/3/2021
但价值不一。它是如何绑定到的?fn2T&&
0赞 songyuanyao 12/3/2021
@TheScore 对不起,我忘了提到采用左值引用的重载。
2赞 TheScore 12/3/2021
谢谢你的编辑完美地回答了我的疑问。