Подтвердить что ты не робот

Почему std:: declval добавляет ссылку?

std::declval - утилита времени компиляции, используемая для построения выражения с целью определения его типа. Он определяется следующим образом:

template< class T >
typename std::add_rvalue_reference<T>::type declval() noexcept;

Не проще ли это?

template< class T >
T declval() noexcept;

В чем преимущество ссылочного типа возврата? И не следует ли это называть declref?

Самый ранний исторический пример, который я нахожу, n2958, который вызывает функцию value(), но уже всегда возвращает ссылку.

Обратите внимание, что операнд decltype не должен иметь доступный деструктор, т.е. он не семантически проверяется как полное выражение.

template< typename t >
t declprval() noexcept;

class c { ~ c (); };
decltype ( declprval< c >() ) * p = nullptr; // OK
4b9b3361

Ответ 1

"Нет временного введения для возврата функции prvalue типа объекта в decltype" правило применяется только в том случае, если сам вызов функции является либо операндом decltype, либо правым операндом оператора запятой, что операнд decltype (§5.2.2 [expr.call]/p11), что означает, что данный declprval в OP,

template< typename t >
t declprval() noexcept;

class c { ~ c (); };

int f(c &&);

decltype(f(declprval<c>())) i;  // error: inaccessible destructor

не компилируется. В более общем плане возврат T предотвратит большинство нетривиальных применений declval с неполными типами, тип с частными деструкторами и т.п.:

class D;

int f(D &&);

decltype(f(declprval<D>())) i2;  // doesn't compile. D must be a complete type

и это не имеет особого преимущества, поскольку значения x почти не отличаются от prvalues, за исключением случаев, когда вы используете decltype на них, и обычно вы не используете decltype непосредственно для возвращаемого значения declval - вы знаете, тип уже.

Ответ 2

Массивы не могут быть возвращены значением, поэтому даже объявление функции, возвращающей массив по значению, является недопустимым кодом.

Однако вы можете вернуть массив по ссылке.

Ответ 3

Цель decltype() состоит в том, чтобы иметь выражение, которое действует как допустимое значение типа T, чтобы выразить его как T в выражениях, ожидающих T s. Проблема в том, что в С++ тип T может быть не скопированным или даже нестандартным по построению. Поэтому использование T{} для этой цели не работает.

То, что decltype() заключается в возврате ссылки rvalue на T. Ссылка rvalue должна быть действительна для любого типа T, поэтому она гарантирует, что у нас есть действительный T из ссылки rvalue T, и, как он гарантирует, мы можем иметь ссылку rvalue для любого типа T. Это трюк.

Подумайте о decltype() как "дайте мне действительное выражение типа T". Конечно, его использование предназначено для разрешения перегрузки, определения типа и т.д.; так как его цель - вернуть правильное выражение (в синтаксическом смысле), чтобы не возвращать значение. То, что отражено в том, что std::declval() вообще не определено, его только объявлено.
Если он был определен, мы снова имеем исходную проблему (мы должны построить значение для произвольного типа T, и это невозможно).