Search code examples
c++c++14stdasync

Why can't `std::async` pick the correct overload?


Please consider the following example:

#include <iostream>
#include <future>

std::size_t calc_something(std::size_t lim_)
{   
    std::size_t result = lim_ * 10;
    return result;
}

void calc_something(std::size_t lim_, std::promise<std::size_t> &promise_)
{   
    std::size_t result = lim_ * 10;
    promise_.set_value(result);
}

void async_calc()
{
    std::future<std::size_t> async_calc = std::async(calc_something, 5);
    std::cout<< "async_calc = " << async_calc.get() <<std::endl;
}

I am still new to multi-threading, but why -on earth- can't std::async pick the correct overload? The second overload uses a reference to an std::promise object.

I've looked at this question here but it doesn't explain why. Also, I do not get an ambiguity error.

The error I get is:

error: no matching function for call to 'async' std::future<std::size_t> async_calc = std::async(calc_something, 5);

Solution

  • Overload resolution happens based on types of arguments specified at the call site. When you're calling std::async, you're not calling calc_something but passing a pointer to the function to std::async. There are no calc_something call arguments and no way to resolve which of the two overloads' address to pass to std::async.

    The compiler cannot use the subsequent arguments of std::async to resolve the overload. From the compiler's perspective, all std::async arguments are unrelated and nothing implies they will be used to invoke calc_something. In fact, you can call std::async with arguments of types different from those calc_something accepts, and it will work because they will get converted when calc_something is invoked.

    In order to resolve this ambiguity, you must explicitly cast the pointer to calc_something to the exact type of the function pointer, matching one of the overloads.

    std::async((std::size_t (*)(std::size_t))calc_something, 5);