Because if T
is a function template argument, then T&
is a non-constant reference to T
while T&&
is called a forwarding reference if used as type for a function argument. Other T&&
, e.g. in template<typename T> void foo(std::vector<T&&> x)
is really an r-value reference that cannot deduce const (not that const r-value references are very useful).
Since we want to automatically differentiate between the following cases:
const int x = 5; foo(x);
int x = 5; foo(std::move(x));
int x = 5; foo(x);
foo(int{5})
;
while retaining a single template<typename T> foo(T&& x)
definition, forwarding references were given the ability to deduce const
.
As to why T&
cannot deduce const
, it likely never was the intent of this feature. It really meant to serve as a non-constant reference to a generic type. It would make x.non_const_member()
fail to compile sometimes.
Yes, that happens for T&&
too but the intent here is exactly about forwarding the type as it was passed to us to somewhere else, not necessarily modifying the object ourselves.