Почему перегрузка const&& as_const удалена?

В блоге о прогрессе C++17 я прочитал следующее:

P0007 предлагает шаблон вспомогательной функции as_const, который просто берет ссылку и возвращает ее как ссылку на const.

template <typename T> std::add_const_t<T>& as_const(T& t) { return t }
template <typename T> void as_const(T const&&) = delete;

Почему перегрузка const&& удалена?


person Ralph Tandetzky    schedule 02.01.2016    source источник


Ответы (1)


Подумайте, что произошло бы, если бы у вас не было этой перегрузки, и попробуйте передать const rvalue:

template <typename T> const T &as_const(T &t) { return t; }
struct S { };
const S f() { return S{}; }
int main() {
  // auto & ref = as_const(S()); // correctly detected as invalid already
  auto & ref = as_const(f()); // accepted
}

Это будет принято, потому что T будет выводиться как const S, а временные файлы могут быть привязаны к const S &. В результате вы случайно получите ссылку lvalue на временный объект, который будет уничтожен сразу после инициализации ref. Почти все пользователи, принимающие lvalue (будь то переменные или параметры функции), не ожидают, что им будут переданы временные значения; молчаливое принятие временных ссылок означает, что вы легко получаете висящие ссылки.

person Community    schedule 02.01.2016
comment
@dyp Да, именно так, иначе это не было бы проблемой. :) Возможно, мне следует немного расширить это. Спасибо, Т.С. Кстати, для редактирования у меня изначально был пример с xvalue, но я забыл обновить текст, когда упростил пример. - person ; 02.01.2016
comment
Да, мой комментарий предназначался скорее как дополнительное объяснение вашего ответа. Однако я не уверен, полезно ли это ограничение; as_const(T const&&) может просто вернуть T const&&, а предупреждение компилятора о привязке переменной T const& к T const&& в определении переменной не продлевает время жизни. - person dyp; 02.01.2016
comment
@dyp Тогда может быть просто as_const(T &&) (там нет const), который возвращает перегрузку T const &&. Да, это было бы возможно, но я подозреваю, что вызов as_const и передача rvalue, скорее всего, будет ошибкой, чем чем-то, что нужно поддерживать. - person ; 02.01.2016
comment
В мотивации есть пример про ADL между void foo(const T&) и bool foo(T&), поэтому удаленная версия не позволяет выбирать между void foo(const T&&) и bool foo(T&&)... - person Jarod42; 02.01.2016
comment
@ Jarod42 Я не понимаю твоего комментария. Насколько я понимаю, если у вас есть T &t, вы можете вызвать foo(t) (ваша вторая перегрузка) или foo(const_cast<const T &>(t)) (ваша первая перегрузка). Раздел мотивации описывает основное использование as_const: сделать возможным написать foo(as_const(t)), чтобы получить первую перегрузку. Это не связано с удаленной перегрузкой as_const. - person ; 02.01.2016
comment
@hvd: я имею в виду, что foo(temp()) против foo(as_const(temp())), вы не можете использовать второй. - person Jarod42; 02.01.2016
comment
@ Jarod42 Jarod42 Ах, да, я имел в виду, что это скорее ошибка, чем то, что нужно поддерживать. :) Я не могу придумать допустимого варианта использования отдельных перегрузок foo(T &&) и foo(const T &&) или отдельных перегрузок foo(T &&) и foo(const T &), где вы когда-нибудь захотите вызвать версию const с temp() в качестве аргумента. Я упускаю из виду какой-то очевидный вариант использования, который вы видите? - person ; 02.01.2016
comment
Я тоже не вижу, но это не для того, чтобы не было дел - person Jarod42; 02.01.2016