0

I am working on a piece of multi threaded code but I can't seem to pass a std::function object to the std::async function. I'm sure I am doing something wrong but I can't figure out what that would be. Therefore, I prepared this piece of code so maybe someone who knows could help me.

Test1 demonstrates that this std::function object works.
Test2 contains the thing I want it to do; only I wrapped the function object into a lambda.
Test3 contains the example I can't figure out.

std::function<void(AsyncFunctionExample&)> current_function;

void Test1() {
  current_function = &AsyncFunctionExample::Function1;
  while(current_function != nullptr)
    current_function(*this);
}

void Test2() {
  current_function = &AsyncFunctionExample::Function1;
  while(current_function != nullptr)
    const std::future<void> function_future = std::async([&](){current_function(*this);});
}

void Test3() {
  current_function = &AsyncFunctionExample::Function1;
  while(current_function != nullptr)
    const std::future<void> function_future = std::async(current_function, *this);
}

The full code for this example can be found here. The Stackoverflow editor Warned that I am not allowed to dump a full file of code so that's why I boiled it down to its essentials over here.

The compiler error I receive is:
no matching function for call to 'async(std::function&, AsyncFunctionExample&)' const std::future function_future = std::async(current_function, *this);

This doesn't help me a lot. It basically explains to me that there is no signature that matches my call. But I can't figure out from this error what part of my call is wrong and I don't understand how to change it so it would work.

MaestroMaus
  • 342
  • 1
  • 6
  • 18
  • `Test2` is the way to do what you want. – NathanOliver Aug 15 '19 at 13:22
  • It seems Test3 should be possible though. This question deals with a similar topic and it works there: https://stackoverflow.com/questions/19079179/can-stdasync-call-stdfunction-objects But maybe there is something I am missing. If there is please explain. – MaestroMaus Aug 15 '19 at 13:25
  • What *is* `current_function`? Please create a [mcve] to show us. And when asking about build errors, please include the *full* and *complete* error output, including possible informational notes. The full error output could contain hints about the problem. – Some programmer dude Aug 15 '19 at 13:25
  • 1
    Also, why the loop `while(current_function != nullptr)`? In the example you show that loop makes no sense. – Some programmer dude Aug 15 '19 at 13:26
  • Note that unless you store the `future` somewhere or otherwise do something before the end of your loop (where `function_future` will be destroyed) the destruction of `std::async`'s return value will block until the function finishes. Effectively, it won't be asynchronous. – François Andrieux Aug 15 '19 at 13:30
  • I added a pastebin link with the full example. As noted in the text; the stack overflow editor specifically stated that I am not allowed to paste a file worth of content or a big chunk of code. That's why I boiled it down to its barest essentials. – MaestroMaus Aug 15 '19 at 13:31

1 Answers1

4

You can't pass a reference through std::async as it needs to copy the value. You can fix this with std::ref:

const std::future<void> function_future = std::async(current_function, std::ref(*this));

Alternatively just change your function to:

std::function<void(AsyncFunctionExample*)> current_function;

Then you can pass this directly:

const std::future<void> function_future = std::async(current_function, this);
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • And we have a winner; hank you so much! Can you explain me how I could have figured this out myself? – MaestroMaus Aug 15 '19 at 13:37
  • 1
    @MaestroMaus ...by learning and experience. After doing the job for some years, you will notice that your questions you cannot solve by yourself (or google) become more complicated. (That's the effect of learning.) Or, you just use simpler solutions for your problems. (That's the effect of experience.) ;-) – Scheff's Cat Aug 15 '19 at 13:45
  • 1
    @MaestroMaus yep just experience, if you think a bit about how `std::async` must be implemented its reasonably obvious it will need to copy or move its parameters. Then you'll remember all the times you've tried to pass a reference to `std::bind` or simlar and remember having to wrap in `std::ref`. Of course with c++11 you rarely need to use `std::bind` any more so there are fewer opportunities to encounter `std::ref` – Alan Birtles Aug 15 '19 at 13:57