Passing arguments to std::async by reference fails

Related searches

I've noticed that it's impossible to pass a non-const reference as an argument to std::async.

#include <functional>
#include <future>

void foo(int& value) {}

int main() {
    int value = 23;
    std::async(foo, value);
}

My compiler (GCC 4.8.1) gives the following error for this example:

error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’

But if I wrap the value passed to std::async in std::reference_wrapper, everything is OK. I assume this is because std::async takes it's arguments by value, but I still don't understand the reason for the error.

It's a deliberate design choice/trade-off.

First, it's not necessarily possible to find out whether the functionoid passed to async takes its arguments by reference or not. (If it's not a simple function but a function object, it could have an overloaded function call operator, for example.) So async cannot say, "Hey, let me just check what the target function wants, and I'll do the right thing."

So the design question is, does it take all arguments by reference if possible (i.e. if they're lvalues), or does it always make copies? Making copies is the safe choice here: a copy cannot become dangling, and a copy cannot exhibit race conditions (unless it's really weird). So that's the choice that was made: all arguments are copied by default.

But then, the mechanism is written so that it actually fails to then pass the arguments to a non-const lvalue reference parameter. That's another choice for safety: otherwise, the function that you would expect to modify your original lvalue instead modifies the copy, leading to bugs that are very hard to track down.

But what if you really, really want the non-const lvalue reference parameter? What if you promise to watch out for dangling references and race conditions? That's what std::ref is for. It's an explicit opt-in to the dangerous reference semantics. It's your way of saying, "I know what I'm doing here."

Perfect Forwarding to Async Lambdas (Part 1), args Arguments passed to the call to fn (if any). Their types shall be move- constructible. (see std::ref for a wrapper class that makes references copyable). They do not look at how that argument will eventually be used. So, to pass an object by reference you need to tell std::async that you're using a reference. However, simply passing a reference won't do that. You have to use std::ref(value) to pass value by reference.

std::async (and other functions that do perfect forwarding) look at the type of the argument that you pass to figure out what to do. They do not look at how that argument will eventually be used. So, to pass an object by reference you need to tell std::async that you're using a reference. However, simply passing a reference won't do that. You have to use std::ref(value) to pass value by reference.

async - C++ Reference, async( std::launch policy, Function&& f, Args&& args ); (also passed as rvalues) in the current thread (which does not have to be the thread that and the implementation is unable to start a new thread (if the policy is async|deferred If the std::future obtained from std::async is not moved from or bound to a reference, the� To Pass arguments to thread’s associated callable object or function just pass additional arguments to the std::thread constructor. By default all arguments are copied into the internal storage of new thread. Lets look at an example. Passing simple arguments to a std::thread in C++11

The issue itself is only marginally related to std::async(): When defining the result of the operation, std::async() uses std::result_of<...>::type with all its arguments being std::decay<...>::type'ed. This is reasonable because std::async() takes arbitrary types and forwards them to store them in some location. To store them, values are needed for the function object as well as for the arguments. Thus, std::result_of<...> is used similar to this:

typedef std::result_of<void (*(int))(int&)>::type result_type;

... and since int can't be bound to an int& (int isn't an lvalue type was is needed to be bound to int&), this fails. Failure in this case means that std::result_of<...> doesn't define a nested type.

A follow-up question could be: What is this type used to instantiate std::result_of<...>? The idea is that the function call syntax consisting of ResultType(ArgumentTypes...) is abused: instead of a result type, a function type is passed and std::result_of<...> determines the type of the function called when that function type is called with the given list of arguments is called. For function pointer types it isn't really that interesting but the function type can also be a function object where overloading needs to be taken into account. So basically, std::result_of<...> is used like this:

typedef void (*function_type)(int&);
typedef std::result_of<function_type(int)>::type result_type; // fails
typedef std::result_of<function_type(std::reference_wrapper<int>)>::type result_type; //OK

std::async, To Pass arguments to thread's associated callable object or function Passing simple arguments to a std::thread in C++11 Even if threadCallback accepts arguments as reference but still changes done it are not visible outside the thread . C++11 Multithreading – Part 9: std::async Tutorial & Example� So if you want to affect the value of the variable itself, you have to pass a reference to the variable and not its value, which is what [ref] does. And yeah, you have to pass it explicitly with [ ref ] or pass it a variable that itself stores a reference to another variable.

C++11 Multithreading – Part 3: Carefully Pass Arguments to Threads , Asynchronous operations will not fail with an error condition that indicates If the parameter is declared as a non-const reference, const pointer or not accept any arguments, and contains values to be passed as arguments to the user- supplied handler. the initiating function returns a std::future templated on result_type . Passing parameters by references in C++ - We have discussed how we implement call by reference concept using pointers. Here is another example of call by reference which makes use of C++ reference −

Requirements on asynchronous operations, 2) Calls a function f with arguments args according to a specific launch policy policy: If the async flag is set (i.e. (policy & std:: launch:: async)! = 0), then async executes the callable object f on a new thread of execution (with all thread-locals initialized) as if spawned by std:: thread (std:: forward < F > (f), std:: forward < Args > (args)

With passing by reference, it is now possible to change more than one variable given in the function parameter. In addition, one variable can be returned through the functions return value (often a status, success/fail or the most important variable).

Comments
  • No need to type out std::reference_wrapper. Use std::ref.
  • I do use std::ref, but thanks for a hint :)
  • You'll have to dig in the source code of libstdc++ if you're interested in the reason for this error: gcc.gnu.org/onlinedocs/gcc-4.8.1/libstdc++/api/… The line numbers to look at are in the errors. Good luck.
  • When using libc++ a similar error emerges, i.e., it seems to be intentional. I couldn't find the clause in the standard mandating this behavior, however. Also, note that just using std::ref() doesn't solve the problem: it creates a different one! You now need to make sure that the reference variable stays around long enough.
  • +1 IMHO this post is the one that really dissects the error message shown in the OP.