There are two elements at work here:
- Type: The parameter
i
has typeint&&
, or "rvalue reference toint
", where "rvalue reference" is the name for the&&
feature, allowing binding rvalues to a reference; - Value category: This is the key.
i
has a name and so the expression naming it is an lvalue, regardless of its type or what the standard committee decided to call that type. :)
(Note that the expression that looks like i
has type int
, not int&&
, because reasons. The rvalue ref is lost when you start to use the parameter, unless you use something like std::move
to get it back.)