Почему не переадресация ссылки const? - PullRequest
5 голосов
/ 21 июня 2019

Ссылка для пересылки должна передавать аргумент другой функции, верно? Так почему же это не const?

template <typename T>
void func(const T&&);

Неконстантная ссылка позволяет функции изменять свои аргументы (вместо того, чтобы просто пересылать их).

1 Ответ

9 голосов
/ 21 июня 2019

Почему бы не переадресовать ссылочный констант?

Поскольку желательно иметь возможность переместить идеально перенаправленное значение x.Обычно объект не может быть перемещен из константной ссылки, потому что аргумент конструктора перемещения должен быть неконстантным.

Кроме того, желательно иметь возможность связывать lvalues ​​в пересылаемые ссылки.Невозможно связать lvalues ​​в const T&&, который является ссылкой на постоянное значение - это вообще не ссылка на пересылку 1 .

Если вы не хотите уходить отаргумент, но только постоянно ссылаться на него, тогда вам не нужна ссылка для пересылки.В этом случае достаточно ссылки на постоянное значение.

Пример:

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

Здесь мы хотим, чтобы bararg был перемещен в fooarg в случаях 2 и 3, и мы желаем этогодолжно быть скопировано в случае 1. Ссылка для пересылки достигает этого.Ссылка на const rvalue этого не делает, потому что невозможно передать ссылку на const конструктору перемещения.


Ссылки на const rvalue используются редко.Стандартная библиотека использует их в нескольких местах :

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;

Целью этих удаленных перегрузок является предотвращение вызова функции с временным аргументом (rvalue).const предотвращает превращение аргумента в ссылку для пересылки, которая связывает что-либо и, следовательно, делает любой вызов удаленным.

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;

Выше const rvalue ссылка используется в качестве возвращаемого типа оболочки при доступе купакованное значение, так что категория значения и константа переносимого значения сохраняются.


1 Стандарт (черновик) говорит:

[temp.deduct.call] ... Ссылка для пересылки - это rvalue-ссылка на cv-unqualified параметр шаблона, который не представляет параметр шаблона шаблона класса (во время вывода аргумента шаблона класса ([over.match.class.deduct])).Если P является ссылкой для пересылки, а аргумент является lvalue, тип «lvalue ссылка на A» используется вместо A для вывода типа.

...