2015-08-24 24 views
5

W sytuacji, która jest dość interesująca, ponieważ kod, nad którym pracuję, jest kompilowany, mimo że jestem zaskoczony, że to robi, dlatego chciałbym Cię poprosić o twoje ujęcie.Automatycznie generowany konstruktor ruchu z niezmiennymi elementami

Sytuacja jest taka. Mam klasy z usuniętych przenosić i kopiować konstruktorów, który ma operatory przypisania zdefiniowane przez użytkownika:

struct A { 
    A() { } 
    A(const A&) = delete; 
    A(A&&) = delete; 

    A& operator=(const A&) { return *this; } 
    A& operator=(A&&) { return *this; } 
}; 

I mam innej klasy z A jako jedynego członka. W tej klasie I zdefiniowany konstruktor kopiujący ale trzymałem konstruktora poruszają się domyślnie zdefiniowany operator przypisania poprzez wywołanie funkcji wymiany:

class B{ 
public: 
    A a; 

    B() 
    : a{} 
    { } 

    B(const B&) 
    : a{} 
    { } 

    B(B&& other) = default; 
}; 

int main() { 
    B b1; 
    B b2(std::move(b1)); // compiles?? 
} 

Dlaczego praca konstruktor domyślny posunięcie, zważywszy, że nie można po prostu zadzwonić przenieść lub skopiować konstruktora A? Używam gcc 4.8.4.

Odpowiedz

7

Moja oryginalna odpowiedź była błędna, więc zaczynam od nowa.


w [class.copy] mamy:

zalegającego kopii/ konstruktor ruch dla klasy X jest określona jako usunięte (8.4.3) jeśli X zawiera:
- [...]
- potencjalnie skonstruowany podobiekt typu M (lub jego tablica), którego nie można kopiować/przenosić, ponieważ przeciążenie (13.3), zastosowane do odpowiedniego konstruktora M, prowadzi do niejednoznaczności lub do funkcji usunięty lub niedostępne z niewykonaniem konstruktora
- [...]

To podpunkt dotyczy B(B&& other) = default; tak, że konstruktor ruch jest zdefiniowany jako usunięte. To wydaje się złamać kompilację z std::move(), ale mamy także (poprzez uchwały defect 1402):

zalegającego konstruktor ruch, który jest zdefiniowany jako usunięta ignorowane uchwałą przeciążeniowym (13.3, 13.4). [Uwaga: Konstruktor usuniętego ruchu w przeciwnym razie zakłócałby inicjalizację z wartości r, która może zamiast tego używać konstruktora kopii . -end note]

Ignorowanie jest kluczem. Tak więc, gdy robimy:

B b1; 
B b2(std::move(b1)); 

Choć konstruktor ruch dla B zostanie usunięta, kod ten jest dobrze sformułowany, ponieważ konstruktor ruch po prostu nie uczestniczy w rozwiązywaniu przeciążeniowym i konstruktor kopia jest nazywany zamiast. Tak więc, B jest MoveConstructible - nawet jeśli nie można go zbudować za pomocą konstruktora ruchu.

+0

Dodałem kilka corków do kopii i przydziału i wydaje się, że potwierdzasz swoją hipotezę, że nie można poprawnie skompilować konstruktora ruchu, to po prostu wraca do kopii.Nie jestem ekspertem od subtelności standardu, ale wygląda na to, że deklaracja domyślna zachowuje się jak SFINAE w szablonie. – Triskeldeian

+0

Domyślny konstruktor ruchu zdefiniowany jako usunięty jest ignorowany przez rozdzielczość przeciążania. Zobacz N4527 [class.copy]/p11; również [N3667] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3667.html) –

+0

@ T.C. Nowa odpowiedź brzmi poprawnie? – Barry

Powiązane problemy