Code: Select all
// Here, F() requires an lvalue reference. It's type is known and we have a single &
void F( int& );
// Here, F() requires an rvalue reference. It's type is known and we have a double &&
void F( int&& );
// Here, F() can take either an lvalue or rvalue reference. It's type is unknown and we have a double &&
template<typename T> void F( T&& );
// So what about this F()?
template<typename T>
class A
{
public:
void F( T&& );
};
In case you're wondering, a universal reference or forwarding reference is whatever type of reference is passed to it.
Using the previous universal reference example above:
int num = 42;
F( num ); <-- named variable is lvalue so F( T&& ) is actually: F( int& );
F( 69 ); <-- unnamed variable is rvalue so F( T&& ) is actually: F( int&& );
F( A<int>{} ) <-- still unnamed, F( T&& ) is actually F( A<int>&& );
A<int> a;
F( std::move( a ) ) <-- a is returned from function as rvalue so F( T&& ) is F( A<int>&& );
This allows developers to write a single template function and the compiler will be able to pass either a lvalue or rvalue reference instead of programmer having to write two separate functions.
This also explains why std::vector and other containers that have a push or push_back function have one for lvalue ( copy ) and rvalue ( move ), it's because std::vector<> is templated on a type and push/push_back piggy backs off that T.
Gah, what a waste though. I was working on a Signal/Slot class ( similar to chili's Dispatch class from the Discord channel ), and was having trouble passing in callback functions. The reason was due to the template arguments were for the class and not the functions that store my function objects.