20 Stimmen

Warum wird "declval" als "add_rvalue_reference<T>::type" und nicht als "T&&" angegeben?

§20.2.4 [declval]

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

Warum verwenden add_rvalue_reference hier?

De §20.9.7.2 [meta.trans.ref] auf add_rvalue_reference :

Si T einen Objekt- oder Funktionstyp nennt, dann ist das Mitglied typedef type soll heißen T&& ; sonst, type soll heißen T . [ Anmerkung: Diese Regel spiegelt die Semantik der Referenzkollabierung (8.3.2) wider. Zum Beispiel, wenn ein Typ T benennt einen Typ T1& der Typ add_rvalue_reference<T>::type ist keine rvalue-Referenz. -Ende Anmerkung ]

Desde add_rvalue_reference soll ohnehin das Kollabieren von Referenzen widerspiegeln, warum also nicht einfach die T&& wie die folgenden?

template<class T>
T&& declval();

Was kann schon schiefgehen? Was genau sind die Unterschiede zwischen den beiden Versionen?

18voto

Pubby Punkte 50647

Ich weiß nicht, ob das der eigentliche Grund ist, aber add_rvalue_reference hat ein anderes Verhalten für void .

add_rvalue_reference<void>::type ist einfach void .

void&& ist ein Fehler.

11voto

Howard Hinnant Punkte 191035

Mehrere Definitionen hängen ab von declval mit angemessenen Ergebnissen für cv-qualifiziert void . Ein Beispiel ist is_assignable :

template <class T, class U>
struct is_assignable;

Der Ausdruck declval<T>() = declval<U>() i als unbewerteter Operand behandelt wird ...

Die Absicht ist, dass sich "wohlgeformt" auf die Wohlgeformtheit des Zuweisungsausdrucks bezieht, und nicht darauf, ob declval<T> selbst wohlgeformt ist. Das heißt, wir wollen uns nur um eine Sache auf einmal kümmern.

11voto

Der Unterschied besteht darin, dass add_rvalue_reference<> fügt eigentlich nur die && Teil wenn T ist ein Objekt- oder Funktionstyp. Wenn T kein Objekt- oder Funktionstyp ist (z. B. void ) wollen Sie nicht hinzufügen && .

Siehe dieses Beispiel auf Ideone .
Diese Webseite der Implementierung von Boost erklärt:

Die Rolle der Funktionsvorlage declval() ist eine Transformation eines Typs T in einen Wert umwandeln, ohne diese Funktion zu verwenden oder auszuwerten. Der Name soll die Aufmerksamkeit des Lesers auf die Tatsache lenken, dass der Ausdruck declval<T>() ist ein l-Wert, wenn und nur wenn T ist eine l-Wert-Referenz, ansonsten ein r-Wert. Um die Domäne dieser Funktion zu erweitern, können wir ihre Deklaration ein wenig verbessern, indem wir sie ändern in

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

was sicherstellt, dass wir auch cv verwenden können void als Template-Parameter.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X