【问题标题】:How to forward a mutable lambda如何转发可变 lambda
【发布时间】:2021-10-15 17:24:55
【问题描述】:

这是我尝试编译的代码的淡化示例:

#include <iostream>
#include <functional>

template <class F>
auto foo(F&& fun)
{
    return [callback = std::forward<F>(fun)](auto&&... args) {
        std::invoke(callback, std::forward<decltype(args)>(args)...);
    };
}

int main()
{
    std::string cur("running"), target("ok");
    
    foo([s1 = cur, s2 = target](std::string const& arg) /*mutable*/ {
        if (s1 == arg)
        {
            std::cout << s1 << std::endl;
        }
    })("not ok");
    
    return 0;
}

简单地说,我有一个函数foo,它接受可调用对象,并且应该从它们构建一个新的可调用对象。为了这个例子,上面我只是调用fun 参数,但在实际情况下,对可调用对象进行了一些修饰,结果被放入在某些条件下调用此类“动作”的数据结构中。

这个例子compiles and works just fine在尝试将可变 lambda 传递给 foo 时会出现问题。当我取消注释上面的 mutable 关键字时,我得到这个编译错误:

main.cpp: In instantiation of 'foo<main()::<lambda(const string&)> >(main()::<lambda(const string&)>&&)::<lambda(auto:1&& ...)> [with auto:1 = {const char (&)[7]}]':

main.cpp:21:7:   required from here

main.cpp:8:20: error: no matching function for call to 'invoke(const main()::<lambda(const string&)>&, const char [7])'

    8 |         std::invoke(callback, std::forward<decltype(args)>(args)...);

      |         ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from main.cpp:2:

/usr/local/include/c++/11.2.0/functional:94:5: note: candidate: 'template<class _Callable, class ... _Args> std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...)'

   94 |     invoke(_Callable&& __fn, _Args&&... __args)

      |     ^~~~~~

/usr/local/include/c++/11.2.0/functional:94:5: note:   template argument deduction/substitution failed:

In file included from /usr/local/include/c++/11.2.0/bits/move.h:57,

                 from /usr/local/include/c++/11.2.0/bits/nested_exception.h:40,

                 from /usr/local/include/c++/11.2.0/exception:148,

                 from /usr/local/include/c++/11.2.0/ios:39,

                 from /usr/local/include/c++/11.2.0/ostream:38,

                 from /usr/local/include/c++/11.2.0/iostream:39,

                 from main.cpp:1:

/usr/local/include/c++/11.2.0/type_traits: In substitution of 'template<class _Fn, class ... _Args> using invoke_result_t = typename std::invoke_result::type [with _Fn = const main()::<lambda(const string&)>&; _Args = {const char (&)[7]}]':

/usr/local/include/c++/11.2.0/functional:94:5:   required by substitution of 'template<class _Callable, class ... _Args> std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...) [with _Callable = const main()::<lambda(const string&)>&; _Args = {const char (&)[7]}]'

main.cpp:8:20:   required from 'foo<main()::<lambda(const string&)> >(main()::<lambda(const string&)>&&)::<lambda(auto:1&& ...)> [with auto:1 = {const char (&)[7]}]'

main.cpp:21:7:   required from here

/usr/local/include/c++/11.2.0/type_traits:2933:11: error: no type named 'type' in 'struct std::invoke_result<const main()::<lambda(const string&)>&, const char (&)[7]>'

 2933 |     using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;

      |           ^~~~~~~~~~~~~~~

知道为什么吗?我的 foo 也可以接受可变 lambda 表达式吗?

【问题讨论】:

    标签: c++ lambda template-meta-programming


    【解决方案1】:

    只需将mutable 添加到foo 内的lambda:

    template <class F>
    auto foo(F&& fun)
    {
        return [callback = std::forward<F>(fun)](auto&&... args) mutable {
                                                                 //^^^
            std::invoke(callback, std::forward<decltype(args)>(args)...);
        };
    }
    

    【讨论】:

    • 但是为什么呢?那个新的 lambda 不是与fun 无关吗?我的意思是我不是试图修改捕获的可调用对象,只是调用它
    • foo 内的 lambda 的 operator() 是 const 限定的,所以 callback 也是 const 限定的,这意味着它不能调用非 const 限定的 operator()
    • 好的,纯粹是mutable,原来的lambda已经删除了它的const operator()(),所以foo不能调用它——或者更确切地说,这个运算符一开始就不存在,而foo有没什么好打电话的。谢谢有道理
    • 那个foo例程能否根据fun参数是否为mutable添加mutable?一种手动“传递可变”。
    • @Eljay 恐怕不行,但是 C++20 bind_front can 这样做是因为它有四个不同的限定 operator()
    猜你喜欢
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2020-06-22
    • 2015-01-06
    • 2014-11-11
    • 2014-07-25
    相关资源
    最近更新 更多