2016-01-22 16 views
9

mi chiedo quali parti dello standard specificano che nel segmento di codice seguente:C++: conversioni di riferimenti lvalue e rvalue riferimento

#include <memory> 

class A { }; 

class B : public A { }; 

int main() 
{ 
    std::unique_ptr<B> bptr = std::make_unique<B>(); // (a) 
    std::unique_ptr<A> aptr = std::move(bptr);  // (b) 
    std::unique_ptr<A> &aptr_r = bptr;    // (c) 
    std::unique_ptr<A> &&aptr_rr = std::move(bptr); // (d) 
    return 0; 
} 

(d), compila e (c) non lo fa. Si prega di includere le parti rilevanti dello standard nella risposta o di fare riferimento ad esse in modo appropriato. Solo per riferimento, Ubuntu versione 3.6.2-1 clang (tag/RELEASE_362/def) (sulla base di LLVM 3.6.2) mi dà

error: non-const lvalue reference to type 'unique_ptr<A>' cannot 
     bind to a value of unrelated type 'unique_ptr<B>' 
     std::unique_ptr<A> &aptr_r = bptr; 
         ^  ~~~~ 

e gcc (Ubuntu 5.2.1-22ubuntu2) 5.2 .1 20.151.010 mi dà

error: invalid initialization of reference of type ‘std::unique_ptr<A>&’ 
     from expression of type ‘std::unique_ptr<B>’ 
     std::unique_ptr<A> &aptr_r = bptr; 
            ^

Edit:

per rendere la mia domanda più chiaro, permettetemi di aggiungere

class C { }; 

std::unique_ptr<C> cptr = std::make_unique<C>(); // (e) 
std::unique_ptr<A> &&aptr_rr2 = std::move(cptr); // (f) 

Che cosa è mantenere (f) dalla compilazione quando (d)? Ovviamente A e C sono correlate, ma dove è che rilevata quando il costruttore std::unique_ptr utilizzato per costruire la temporanea per entrambi (d) e (f) è

template<class U, class E> 
unique_ptr(unique_ptr<U, E> &&u); 
+2

(http://coliru.stacked-crooked.com/a/7e47cee922d95250) – chris

+4

' (c) ' non si compila perché 'aptr_r' e' bptr' sono di tipi diversi, e quindi 'aptr_' non può essere un riferimento diventato di' bptr'. È così: 'int x = 0; float & y = x; '. Ma '(d)' compila perché un oggetto temporaneo del tipo di destinazione, viene creato dall'espressione 'std :: move (bptr)' .. e l'oggetto temporaneo si lega al riferimento di rvalue. Si noti che una volta creato questo riferimento rvalore, 'bptr' diventa nullo, in quanto è stato spostato. – Nawaz

risposta

4

La differenza fondamentale tra le valigie risiede nel fatto che rvalue i riferimenti possono essere vincolati indirettamente (tramite un temporaneo), mentre i riferimenti non-const non possono. In entrambi (c) e (d), l'inizializzatore non è simile o convertibile nel tipo definito in [dcl.init.ref]/(5.1), pertanto [dcl.init.ref]/(5.2) deve essere applicato - Esclusione immediata (c):

caso contrario, il riferimento è un riferimento ad un valore assegnabile const tipo (ad esempio, CV1 è const) non volatile, o il riferimento deve essere un riferimento rvalue.

noti inoltre che unique_ptr<A> e unique_ptr<B> sono distinte, tipi non correlati, indipendentemente da come A e B sono correlati.

Si può osservare che regola with scalars, too: [. Non proprio `unique_ptr`-specifica]

int&& i = 0.f; // Ok 
int& i = 0.f; // Not ok 
Problemi correlati