0xbaadf00d February 2016

return lambda by rvalue ref?

#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;
}

Is it possible and how, to return the "func" variable by rvalue ref?

I have a feeling that this is somehow totally insane, but I'd like to know why, so I can restore my sanity.

I have no idea if i have done something horribly wrong. Please provide feedback.

I built this thing so that I can make callbacks that are actually just posted to the treadpool for processing, without the caller or the target knowing anything about this. The middleman that binds them together makes the choice of how to connect them.

https://ideone.com/4Wfhb1


EDIT

Ok, so I thought that there is copying going on when I return the func variable. But apparently it's dealt with by RVO, so no copying takes place. I have not verified this, but now that I think about it, that would make sense.

Answers


Richard Hodges February 2016

I think what you're trying to do is to move p_function into your lambda while avoiding copies? Presumably this is for performance reasons?

In which case you probably want to write it like this:

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;
}


MikeMB February 2016

If your question is how to return a lamba in the most eficient way, then just return it by value and use automatic return typ deduction:

//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...);
    };
}

This will leverage RVO and avoid any dynamic memory allocations that std::function might have to perform.

Also having an r-value reference parameter usually doesn't gain you anything, if you don't move from it (unless you require that specific interface for another reason). In order to do so here you can leverage c++14's generalized lambda capture (the compiler can't perform that optimization by itself, as p_function itself is an l-value).

Now, if your question on the other hand was, if/how you can return a (r- or l-value) reference to a non-static local variable from a function, then the answer is simply:

NEVER DO THAT!

Post Status

Asked in February 2016
Viewed 2,187 times
Voted 11
Answered 2 times

Search




Leave an answer