2012-12-14 24 views
6

g ++ 4.7 wspiera inicjalizację elementu tablicy i zacząłem grać z nim.inicjalizacja elementu tablicowego typów zdefiniowanych przez użytkownika

Poniższy kod nie został skompilowany.

struct A 
{ 
    A(int){}; 
    A(const A&) = delete; 
    A& operator=(const A&) = delete; 
    ~A(){}; 
}; 

struct B 
{ 
    B(): 
     a{{0},{1}} 
    {}; 
    A a[2]; 
}; 

B b; 

Komunikat o błędzie z gcc 4.8 (prerelease) wynosi:

n.cc: In constructor ‘B::B()’: 
n.cc:12:20: error: use of deleted function ‘A::A(const A&)’ 
      a{{0},{1}} 
      ^
n.cc:4:8: error: declared here 
     A(const A&) = delete; 
     ^

Czy istnieje sposób, aby to działało kodu? Nie mogę łatwo zmienić contructors, destruktor A. Potrzebuję konstruktora ruchu lub konstruktora kopiowania do zainicjowania tablicy, ale wydaje mi się to sprzeczne z intuicją, ponieważ wszystko, czego naprawdę chcę, to budowa na miejscu.

Działa, jeśli podzielę [2] na 2 elementy a0 i a1 i skonstruuję je oddzielnie. Wygląda to jednak podejrzanie.

+0

":" w konstruktorze używa konstruktorów kopii do przypisywania wartości, a usuwa się je w A, co powoduje błąd. –

Odpowiedz

2

Tablice są agregatami, a inicjowanie agregacji zawsze korzysta z inicjowania kopii. C++ 11 §8.5.1/1:

agregat jest tablicą lub klasy bez konstruktorów dostarczane przez użytkowników, bez klamra lub równy-inicjator a za nieprzestrzeganie statyczne elementy danych, brak prywatnych lub chronionych nie statycznych elementów danych, brak klas podstawowych i brak funkcji wirtualnych.

§8.5.1/2:

gdy agregat jest inicjowany przez liście inicjatora, zgodnie 8.5.4, elementy listy inicjatora są traktowane jako inicjalizatory członków agregat, w rosnącym indeksie dolnym lub członku. Każdy element jest inicjowany przy użyciu kopii z odpowiedniej klauzuli inicjującej -klauzula. & hellip;

(kopalni nacisk).

Dodatkowo, kompilator nie pośrednio generować konstruktora ruch Jeżeli konstruktor kopii użytkownika zgłoszony jest obecne (§12.8/9); ponieważ użytkownik ma deklarowany przez użytkownika konstruktor kopii, który jest zdefiniowany jako usunięty, A nie ma konstruktora kopiowania ani przenoszenia. Wyraźnie dodając konstruktora move działa:

struct A 
{ 
    A(int) { } 
    A(A const&) = delete; 
    A& operator = (A const&) = delete; 
    A(A&&) = default; 
    ~A() = default; 
}; 

struct B 
{ 
    B() : a{{0}, {1}} { } 
    A a[2]; 
}; 

int main() 
{ 
    B b; 
} 

Online demo

To jest tak blisko tego, co chcesz, jak masz zamiar dostać.

+0

Nie odpowiedź, na którą liczyłem, ale dzięki za szczegółowe wyjaśnienie. – mirk

4

W ramach agregacji listy (8.5.4p1) agregatu (8.5.1), formą inicjalizacji wykonanej na elementach agregatu jest inicjowanie kopii (8.5.1p2), nawet jeśli inicjalizacja jest bezpośrednim lista inicjalizacja:

gdy agregat jest inicjowany przez liście inicjatora, jak kwoty wskazanej w 8.5.4, elementy listy inicjatora są traktowane jako inicjalizatory członków łącznie w zwiększeniu indeks dolny lub członkostwo.Każdy element jest inicjowany przy użyciu kopii z odpowiedniej klauzuli inicjującej -klauzula.

Jednak tylko dlatego, że inicjalizowana metoda inicjowania kopii nie oznacza, że ​​kopia się pojawi. Zgodnie z copy-list-initialization of non-copyable types, inicjowanie listy kopii powinno być identyczne z inicjowaniem listy bezpośredniej z tym wyjątkiem, że jawne konstruktory nie są dozwolone.

Powiązane problemy