Why isn't forwarding reference const?
Because it is desireable to be able to move a perfectly forwarded xvalue. An object cannot usually be moved from a const reference, because the argument of the move constructor needs to be non-const.
Furthermore, it is desirable to be able to bind lvalues into forwarding references. It is not possible to bind lvalues into const T&&
which is a const rvalue reference - it is not a forwarding reference at all 1.
If you don't wish to move from the argument, but only constantly refer to it, then you don't need a forwarding reference. In that case a const lvalue reference is sufficient.
Example:
struct S {
S() = default;
S(S&&) = default; // move
S(const S&) = default; // copy
};
void foo(S fooarg);
template <typename T>
void bar(T&& bararg) { // forwarding reference
foo(std::forward<T>(bararg));
}
// call site
S s;
bar(s); // 1 copy
bar(S{}); // 2 move
bar(std::move(s)); // 3 move
Here we wish bararg
to be moved into fooarg
in cases 2 and 3 , and we wish it to be copied in case 1. Forwarding reference achieves this. A const rvalue reference does not, because it is not possible to pass the const reference to the move constructor.
Const rvalue references are only rarely useful. Standard library uses them in a few places:
template <class T> void as_const(const T&&) = delete;
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The intention of these deleted overloads is to prevent calling the function with a temporary argument (rvalue). const
prevents the argument from becoming a forwarding reference, which would bind to anything and therefore make any call deleted.
constexpr const T&& optional::operator*() const&&;
constexpr const T&& optional::value() const &&;
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
Above, const rvalue reference is used as a return type of a wrapper when accessing the wrapped value so the value category and constness of the wrapped value is maintained.
1 Standard (draft) says:
[temp.deduct.call] ... A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])).
If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.