Почему «declval» указан в терминах «add_rvalue_reference <T>:: type», а не «T &&»? - PullRequest
17 голосов
/ 21 января 2012

§20.2.4 [declval]

template <class T>
typename add_rvalue_reference<T>::type declval() noexcept; // as unevaluated operand

Зачем здесь add_rvalue_reference

С §20.9.7.2 [meta.trans.ref] по add_rvalue_reference:

Если Tприсваивает имя объекту или типу функции, затем член typedef type должен назвать T&&;в противном случае type назовет T.[ Примечание: Это правило отражает семантику свертывания ссылок (8.3.2).Например, когда тип T называет тип T1&, тип add_rvalue_reference<T>::type не является ссылкой на значение. —конечная заметка ]

Поскольку add_rvalue_reference в любом случае предназначен для отражения свертывания ссылок, почему бы просто не использовать T&&, как показано ниже?*Что может пойти не так?Какие именно различия между двумя версиями?

Ответы [ 3 ]

15 голосов
/ 21 января 2012

Я не знаю, является ли это действительной причиной, но add_rvalue_reference имеет другое поведение для void.

add_rvalue_reference<void>::type просто void.

void&& это ошибка.

10 голосов
/ 21 января 2012

Разница в том, что add_rvalue_reference<> действительно добавляет часть &&, только если T является типом объекта или функции. Если T не является объектом или типом функции (например, void), вы не хотите добавлять &&.

См. этот пример на Ideone .
Эта веб-страница реализации Boost объясняет:

Роль шаблона функции declval() - это преобразование типа T в значение без использования или оценки этой функции. Предполагается, что имя обращает внимание читателя на тот факт, что выражение declval<T>() является lvalue, если и только если T является lvalue-ссылкой, в противном случае - rvalue. Чтобы расширить область этой функции, мы можем сделать немного лучше, изменив ее объявление на

template<class T>
typename std::add_rvalue_reference<T>::type declval(); // not used

, что гарантирует, что мы также можем использовать cv void в качестве параметра шаблона.

10 голосов
/ 21 января 2012

Несколько определений зависят от declval, дающего разумные результаты для cv-квалифицированного void. Примером является is_assignable:

template <class T, class U>
struct is_assignable;

Выражение declval<T>() = declval<U>() хорошо сформировано при обработке как неоцененный операнд ...

Намерение состоит в том, что "правильно сформированный" относится к правильно сформированному выражению присваивания, а не к тому, является ли сам declval<T> правильно сформированным. То есть мы хотим беспокоиться только об одной вещи за один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...