0

The function std::async is defined like so:

template< class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
    async( Function&& f, Args&&... args );

As we can see, it takes both arguments as rvalue-references, or more precisely, as "universal references" (rvalue references to the template argument types).

Passing a simple function pointer (e.g. std::async(myfunction)) works, and I don't understand why.

My understanding is that you can bind an rvalue to a const lvalue reference - but not vice versa. You cannot bind an lvalue to an rvalue reference (without casting it to an rvalue using std::move).

However - when calling std::async(myfunction), the std::async template is instantiated with Function = <some_func_type>, and so becomes std::async<some_func_type>(some_func_type&&). That is - it takes an rvalue reference. However, we pass it an lvalue.

Why does it work?

Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • 4
    universal references are not r-value references, thats how they got their name – 463035818_is_not_an_ai Jul 08 '20 at 15:49
  • 3
    the official name is forwarding reference btw – 463035818_is_not_an_ai Jul 08 '20 at 15:51
  • @idclev463035818 Indeed, but if I understand correctly, the universal reference `Function&&` because `Thing&&` when `Function = Thing`. Correct? – Aviv Cohn Jul 08 '20 at 15:53
  • Note that when `T = int &`, then `T && = int &` (not `int &&`) since, roughly speaking a reference-to-reference is simplified to just reference, and the result is an rvalue reference only in the case "rvalue-reference to rvalue-reference", and is an lvalue reference in all other three cases. Informally, the collapsing rules are `& = & & = && & = & &&` and `&& && = &&`. Hence a type of the form `T &&` can be any kind of reference, rvalue or lvalue, and not just rvalue. – chi Jul 08 '20 at 16:21

1 Answers1

1

As we can see, it takes both arguments as rvalue-references, or more precisely, as "universal references" (rvalue references to the template argument types).

The term "universal reference" (or "forwarding reference") is not a more precise term for rvalue references. It's a different thing.

When you put && on a template parameter type like that, it's a forwarding reference. These will bind to lvalues, by design.

tl;dr: It's not an rvalue reference.

(Okay, it kind of is, but deduction and reference-collapsing rules make it effectively not one, so we don't call it one. Hence the special name for this case: "forwarding reference".)

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35