2012-01-21 9 views
17

§20.2.4 [declval]Perché 'declval' è specificato in termini di 'add_rvalue_reference <T> :: type' e non 'T &&'?

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

Perché usare add_rvalue_reference qui?

Da §20.9.7.2 [meta.trans.ref] su add_rvalue_reference:

If T nomi un tipo di oggetto o di una funzione, allora il membro typedef type chiamerà T&&; altrimenti, type deve essere denominato T. [Nota: Questa regola riflette la semantica del collasso di riferimento (8.3.2). Ad esempio, quando un tiponomina un tipo T1&, il tipo add_rvalue_reference<T>::type non è un riferimento di rvalue. -end nota]

Dal add_rvalue_reference è pensato in modo da riflettere riferimento crollare in ogni modo, perché non utilizzare T&& come la seguente?

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

Cosa potrebbe andare storto? Quali sono esattamente le differenze tra le due versioni?

+1

"Che cosa potrebbe andare storto?" Anatra! –

+3

@LightnessRacesinOrbit: Err ... cosa? Solo perché ho trascurato qualcosa che ho preso -1? Cose interessanti ... – Xeo

+1

@Lightness Ora _that_ è inutile. –

risposta

14

Non so se questo è il motivo reale, ma add_rvalue_reference ha un comportamento diverso per void.

add_rvalue_reference<void>::type è semplicemente void.

void&& è un errore.

+0

Oooh, buon punto. Tuttavia, quando vorresti effettivamente un 'std :: declval ()'? Posso solo immaginare in un'espressione SFINAE 'decltype (t.size(), std :: declval (), std :: true_type)' o qualcosa, ma 'void()' è molto più conveniente e funziona lo stesso. – Xeo

+1

@Xeo forse nelle classi template che consentono 'void' come parametro template? 'modello classe foo {... declval ...}; pippo bar; '. Questo potrebbe essere raro, ma è meglio se funziona quando non ne hai bisogno, piuttosto che se non funziona quando ne hai bisogno. –

+0

Accetterò questo, poiché indica chiaramente cosa mi mancava/trascura: "' void && 'è un errore". – Xeo

10

Diverse definizioni dipendono dallo declval fornendo risultati ragionevoli per qualificata per il cvvoid. Un esempio è is_assignable:

template <class T, class U> 
struct is_assignable; 

L'espressione declval<T>() = declval<U>() è ben formata se trattati come operando non valutata ...

L'intento è che "ben formato" si riferisce al pozzo -formed-of dell'espressione di assegnazione, e non se lo stesso declval<T> sia ben formato. Cioè vogliamo preoccuparci solo di una cosa alla volta.

10

La differenza è che add_rvalue_reference<> aggiunge solo la parte && se T è un oggetto o un tipo di funzione. Se T non è un oggetto o un tipo di funzione (ad esempio void) non si desidera aggiungere &&.

Vedere this example on Ideone.
This webpage of Boost's implementation spiega:

Il ruolo del modello di funzione declval() è una trasformazione di tipo T in un valore senza utilizzare o valutare questa funzione.Il nome dovrebbe dirigere l'attenzione del lettore sul fatto che l'espressione declval<T>() è un lvalue se e solo se T è un riferimento di lvalue, altrimenti un valore di rvalue. Per estendere il dominio di questa funzione si può fare un po 'meglio, cambiando la sua dichiarazione di

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

che assicura che possiamo anche usare cv void come parametro di template.

Problemi correlati