2016-01-22 2 views
9

Интересно, какие части стандарта указать, что в следующем сегменте коды:С ++: степень конверсия именующих ссылок и RValue ссылкой

#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) компилирует и (с) не делает. Пожалуйста, включите соответствующие части стандарта в свой ответ или обратитесь к ним соответствующим образом. Просто для справки, Ubuntu лязг версия 3.6.2-1 (теги/RELEASE_362/финал) (на основе LLVM 3.6.2) дает мне

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; 
         ^  ~~~~ 

и GCC (Ubuntu 5.2.1-22ubuntu2) 5,2 0,1 20151010 дает мне

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:

Чтобы сделать мой вопрос более ясным, позвольте мне добавить

class C { }; 

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

Что удерживает (f) от компиляции, когда (d) делает? Очевидно A и C не связаны между собой, но где, что обнаруживается, когда std::unique_ptr конструктор используется для создания временного для обоих (d) и (е) является

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

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

+4

' (с) ' не компилируется, потому что 'aptr_r' и' bptr' имеют разные типы, и, таким образом, 'aptr_' не может стать ссылкой на' bptr'. Это так: 'int x = 0; float & y = x; '. Но '(d)' компилируется, потому что временный объект целевого типа создается из выражения 'std :: move (bptr)' .. и временный объект привязывается к ссылке rvalue. Обратите внимание, что как только вы создадите эту ссылку rvalue, 'bptr' станет нулевой, поскольку она была перемещена. – Nawaz

ответ

4

Основное различие между вашими дел заключается в том, что RValue ссылки могут связываться косвенно (через временные), а ссылки const lvalue не могут. В обоих (c) и (d) инициализатор не похож или не конвертируется в тип, обозначенный как [dcl.init.ref]/(5.1), поэтому [dcl.init.ref]/(5.2) должен применяться - немедленно исключить (c):

в противном случае, ссылка должна быть именующей ссылкой на энергонезависимой const типа (т.е. CV1 должен быть константным), или ссылка должна быть ссылкой Rvalue.

Отметим также, что unique_ptr<A> и unique_ptr<B> различны, не связанных между собой видов, независимо от того, как A и B связаны.

Вы можете заметить, что правило with scalars, too: [. Не совсем `unique_ptr` конкретных]

int&& i = 0.f; // Ok 
int& i = 0.f; // Not ok 
Смежные вопросы