Maybe this will help you to see it the way the compiler does (apologies to any language lawyers if I am oversimplifying):
In this example, the compiler must infer the type of T to be the type that makes the function declaration legal with the least amount of deduction. Since a T can usually be copy-constructed directly from a const T& (which implies that it can also be copy-constructed from a T&), your function will take a copy.
template<class T>
void foo(T value);
In this example T must be the type of the object thing ref
refers to - and since references cannot refer to references, T must be a (possibly const, possibly volatile) type.
template<class T>
void foo(T& ref);
In this example, ref must be referring to a const (possibly volatile) object of type T:
template<class T>
void foo(const T& ref);
In this example, ref
may either be a reference or an r-value reference. It's known as a universal reference. You're actually writing two functions in one and it's often the most efficient way to handle the case where you are taking ownership of ref
.
template<class T>
void foo(T&& ref);
// called like this:
foo(Bar()); // means ref will be a Bar&&
// called like this:
Bar b;
foo(b); // means ref will be a Bar&
// called like this:
const Bar b;
foo(b); // means ref will be a const Bar&
In summary:
void foo(T value)
means I will make a copy of whatever you give me.
void foo(T& value)
means I wont make a copy but I may modify your value. You may not give me a temporary.
void foo(const T& value)
means I wont make a copy and I cannot modify your copy. You may give me a temporary.
void foo(const T&& value)
means I may steal or modify the contents of your value, even if it's a temporary.