It has been ten years since C++11, which introduced many new language features that further strengthened C++ while discouraging many.

T&& Doesn’t Always Mean “Rvalue Reference”

by Scott Meyers

Scott Meyers once said that T&& does not always represent an rvalue reference.

&& as function arguments

That’s right. The ampersand symbol is probably a point that discouraged many people when they first learned C++ or C++11. But it’s not that hard to figure out.

First of all, in non-template functions, && must represent an rvalue reference, so only rvalue type arguments can be accepted.

class A {
    ...
};
void foo(A&& a) {
    ...
}
Copy the code

The foo function can only take the following rvalue arguments.

foo(A{}); A a; foo(std::move(a)); A get_a() { A a; . return a; } foo(get_a());Copy the code

However, this call is incorrect and will fail to compile:

    A a1;
    A& ar = a1;
    foo(ar); // ERROR
Copy the code

However, && in a template function does not represent an rvalue rreference. Such as:

template <typename T>
void bar(T&& t) {
    ...
}
Copy the code

This T&& is referred to as a forwarding reference in the C++ standard, commonly known as a universal reference and often translated as a universal reference. As the name implies, the parameters it can receive are not only rvalues, but also lvalues, so it is called universal. So T&& in the main problem is not an rvalue reference.

The template function bar(), which I mentioned above, can accept the following types of arguments (any type!) . Such as:

    bar(A{});
    A a;
    bar(move(a));
    bar(get_a());

    A a1;
    A& ar1 = a1;
    bar(ar1);

    const A& ar2 = a1;
    bar(ar2);
Copy the code

However, the && in template functions are not all forward references. Such as:

template<typename T>
void bar(vector<T>&& tv) {
    ...
}
Copy the code

The parameter TV can only accept arguments of rvalue type.

Such as:

template<typename T>
void bar(const T&& v) {
    ...
}
Copy the code

With the const constraint, && is also an rvalue reference and can only be passed as an rvalue…

I’m sure you see the difference.

The && that receives the return value

Another area of confusion for && is not just when it comes to parameters, as described above. There is also ambiguity when receiving the return value from a function, which is often confusing.

class A { ... }; A&& a = test1(); Auto && a = test2(); // This && is also a forward referenceCopy the code

When used with auto and &&, it is also a forward reference (universal reference), so it can accept various types of function arguments.

However, if the type is explicitly specified (such as A) and then used with &&, then only rvalue references are represented and only rvalue arguments are accepted!

How’d it go? Did you get rid of it?