2015-06-29 10 views
5

Non riesco a capire cosa succede esattamente quando si passa un riferimento su funzione a una funzione come riferimento universale (quale tipo viene dedotto). Supponiamo di avere una funzione foo che prende un parametro come riferimento universale:Passaggio di un riferimento alla funzione come riferimento universale

template<typename T> 
void foo(T&& param) 
{ 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
} 

E poi facciamo il seguente:

void(&f)(int) = someFunction; 
foo(f); 

Il risultato sarà:

void foo(T&&) [with T = void (&)int]

Questo è perfettamente comprensibile: stiamo passando lvalue alla nostra funzione foo, quindi il tipo dedotto è nullo (&) int, e il tipo del parametro sarà "void (& & &) int" che sotto riferimento le regole di compressione diventano nulle (&) int. Param sarà solo un riferimento lvalue a una funzione.

Ma quando faccio la seguente:

void(&f)(int) = someFunction; 
foo(std::move(f)); 

foo stamperà:

void foo(T&&) [with T = void (&)int]

che è esattamente la stessa di prima! Cosa sta succedendo qui? Perché il risultato è lo stesso di quando passa lvalue? Mi aspetterei che dato che stiamo passando rvalue a foo, il tipo dedotto dovrebbe essere T = void (int), e param dovrebbe diventare void (& &) int. Questo succede sempre con tutti gli altri tipi "normali" (come classi, tipi primitivi, ecc.) Perché è diverso quando si tratta di riferimenti alle funzioni?

+0

Nah. 'param' ha un nome, è un lvalue per definizione. –

+3

@KerrekSB Scusa ma è sbagliato - http: // StackOverflow.it/questions/7016777/what-is-an-rvalue-reference-to-function-type –

+0

@rubix_addict: Il mio male, grazie! Rimosso. Avevo dopo la dichiarazione che è parte della risposta, ma non ho capito bene. –

risposta

6

A std::move è glorificato static_cast per il tipo di riferimento di rvalore. Lo standard dice che il casting su un valore di riferimento al tipo di funzione produce ancora un lvalue. Per [expr.static.cast]/p1:

Il risultato dell'espressione static_cast<T>(v) è il risultato di convertire l'espressione v di digitare T. Se T è un tipo di riferimento di lvalue o un riferimento di rvalue al tipo di funzione, il risultato è un lvalue;

riguardante la categoria valore della chiamata std::move() funzione che restituisce un riferimento rvalue designa il risultato della conversione, si può anche vedere dal [expr.call]/p10 che una chiamata di funzione è un lvalue se tipo di ritorno è un riferimento rvalue operato tipo:

una chiamata di funzione è un lvalue se il tipo di risultato è un tipo di riferimento lvalue o un riferimento rvalue di tipo funzionare, un xValue se il tipo di risultato è un riferimento di rvalue al tipo di oggetto e un valore di preallarme rwise.

+0

Risposta molto bella. Ha senso intuitivo che il riferimento al tipo di funzione sarebbe trattato in modo leggermente diverso; le funzioni non hanno stato e quindi non possono essere spostate e un riferimento a una funzione non può mai cambiare la funzione. il riferimento ai tipi di funzione si comporta sempre in modo efficace come const &. Anche se mi lascia ancora a chiedermi perché è stato necessario dichiarare esplicitamente che queste conversioni avvengono. Quali esempi di codice strani e privi di senso potrebbero essere inventati in assenza di questa regola? –

+0

Ah, bello! Sembra un po 'complicato quando ci sono molti modi per ottenere quello che sarebbe una funzione xvalue, per dire per ogni modo che in realtà si traduce in una funzione lvalue invece, ma è quello che è. :) – hvd

Problemi correlati