繁体   English   中英

C ++ 11将函数作为lambda参数传递

[英]C++11 Passing function as lambda parameter

最近,我遇到了一个奇怪的问题,即将作为参数传递的函数传递给lambda表达式。 使用clang 3.5+编译的代码很好,但是使用g ++ 5.3失败了,我想知道问题是在c ++标准中,clang中的非标准扩展,还是GCC中的无效语法解释。

示例代码很简单:

    template<typename Fn, typename... Args, typename T = typename std::result_of<Fn(Args...)>::type>
    std::future<T>
    async(Fn &&fn, Args &&... args)
    {
        std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
        auto lambda = [promise, fn, args...](void)
            { promise->set_value(fn(std::move(args)...)); };
        send_message(std::make_shared<post_call>(lambda));
        return promise->get_future();
    };

海湾合作委员会报告如下:

error: variable ‘fn’ has function type
             { promise->set_value(fn(std::move(args)...)); };
(...)
error: field ‘async(Fn&&, Args&& ...) [with Fn = int (&)(int, int); Args = {int&, int&}; T = int]::<lambda()>::<fn capture>’ invalidly declared function type
         auto lambda = [promise, fn, args...](void)

幸运的是,我找到了一个简单的解决方法,添加了一个std :: function对象,封装了function参数:

    template<typename Fn, typename... Args, typename T = typename std::result_of<Fn(Args...)>::type>
    std::future<T>
    async(Fn &&fn, Args &&... args)
    {
        std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
        std::function<T(typename std::remove_reference<Args>::type...)> floc = fn;
        auto lambda = [promise, floc, args...](void)
            { promise->set_value(floc(std::move(args)...)); };
        send_message(std::make_shared<post_call>(lambda));
        return promise->get_future();
    };

虽然我没有完全理解第一段代码中的错误,但是使用clang成功编译并运行时没有错误。


编辑

我刚刚注意到,如果其中一个参数应该是一个参考,我的解决方案就会发生灾难性的失败。 因此,如果您有任何其他可能适用于C ++ 11的建议(即没有专门的lambda捕获[c ++ 14功能]),那真的很酷......

变量fn具有函数类型。 特别是,它的类型为Fn = int (&)(int, int)

类型Fn (不是引用)的值是int(int,int)

无法存储此值。

我模糊地惊讶它不会为你自动腐烂。 在C ++ 14中,您可以:

auto lambda = [promise, fn=fn, args...](void)
        { promise->set_value(fn(std::move(args)...)); };

这应该在内部将fn (外部)的类型衰减到fn 如果这不起作用:

auto lambda = [promise, fn=std::decay_t<Fn>(fn), args...](void)
        { promise->set_value(fn(std::move(args)...)); };

它明确地腐朽了它。 (Decay是一种适合存储的类型的操作)。

其次,你应该添加mutable

auto lambda = [promise, fn=std::decay_t<Fn>(fn), args...](void)mutable
        { promise->set_value(fn(std::move(args)...)); };

或者std::move不会做太多。 (移动const值并没有太大作用)。

第三,你可以转移承诺,而不是创建一个不必要的共享ptr:

template<typename Fn, typename... Args, typename T = typename std::result_of<Fn(Args...)>::type>
std::future<T>
async(Fn &&fn, Args &&... args)
{
    std::promise<T> promise;
    std::future<T> ret = promise.get_future();
    auto lambda =
      [promise=std::move(promise), fn=std::decay_t<Fn>(fn), args...]
      () mutable {
        promise.set_value(fn(std::move(args)...));
      };
    send_message(std::make_shared<post_call>(lambda));
    return ret;
};

这假设你的post_call类可以处理只移动的lambdas(如果它是std::function它不能)。

你的第一个代码在VS2015下编译得很好,所以我无法重现你的问题但是因为你使用的是通用引用,我会尝试类似:

template<typename Fn, typename... Args, typename T = typename std::result_of<Fn(Args...)>::type>
std::future<T> async2(Fn &&fn, Args &&... args)
{
    std::promise<T> prom;
    auto floc = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);
    auto lambda = [&prom, floc](void)
    { prom.set_value(floc()); };
    send_message(std::make_shared<post_call>(lambda));
    return prom.get_future();
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM