通过rvalue ref返回lambda?

时间:2016-02-08 11:34:52

标签: c++ lambda c++14

#include <iostream>
#include <functional>

template <typename... Args>
std::function<void(Args...)> pushToEventLoop(std::function<void(Args...)> && p_function)
{
    auto func = [p_function](Args... args) ->void
    {
        // This is what i would do here, but requires too much source code
        //ThreadPool::enque(std::bind(p_function, args...));
        // This is what i'll do for the sake of the example.
        p_function(args...);
    };
    return func;
}

int main() 
{
    auto function(pushToEventLoop(std::function<void(char const *)>(std::bind(std::printf, std::placeholders::_1))));

    auto function2 = std::bind(function, "Hello World!\n");

    function2();

    return 0;
}

是否有可能以及如何通过rvalue ref返回“func”变量?

我有一种感觉,这在某种程度上是完全疯了,但我想知道为什么,所以我可以恢复我的理智。

我不知道我是否做了一些可怕的错误。请提供反馈。

我构建了这个东西,以便我可以进行实际上刚刚发布到treadpool进行处理的回调,而不会让调用者或目标了解这一点。将他们联系在一起的中间人可以选择如何连接他们。

https://ideone.com/4Wfhb1

修改

好的,所以我认为当我返回func变量时会有复制。但显然它是由RVO处理的,因此不会发生复制。我还没有证实这一点,但现在我考虑一下,这是有道理的。

2 个答案:

答案 0 :(得分:4)

如果您的问题是如何以最有效的方式返回lamba,那么只需按值返回它并使用自动返回简单扣除:

//this will actually return a lmabda and not a std::function
template <typename... Args>
auto pushToEventLoop(std::function<void(Args...)> && p_function)
{
    return [f = std::move(p_function)](Args... args)
    {           
        f(args...);
    };
}

这将利用RVO并避免std::function可能必须执行的任何动态内存分配。

如果你没有从中移动,那么拥有r值参考参数通常不会获得任何东西(除非你因为其他原因需要特定的接口)。为了在这里执行此操作,您可以利用c ++ 14的通用lambda捕获(编译器不能自己执行该优化,因为p_function本身是l值)。

现在,如果你的问题是,如果/如何从函数返回(r-或l-值)对非静态局部变量的引用,那么答案就是:

永远不要这样做!

答案 1 :(得分:3)

我认为你要做的是将p_function移到你的lambda中,同时避免复制?可能这是出于性能原因?

在这种情况下,你可能想要这样写:

template <typename... Args>

// return by value - because RVO will elide copies for us
std::function<void(Args...)> 

// passing by r-value reference... ok no problem there
pushToEventLoop(std::function<void(Args...)> && p_function)
{
    // but I want to MOVE my p_function into func
    // this will require at least c++1y (c++14)
    auto func = [p_function = std::move(p_function)](Args... args) ->void
    {
        // p_function has now been moved into the lambda ...
    };
    // ... p_function passed to us is now in a valid but undefined state
    // so don't use it here

    // allow RVO to do its thing
    return func;
}