Jeśli drugi konstruktor komentarzem, to S {{}} jest nadal ważna ekspresji, ale (pewno) przemieszczają się, konstruktor domyślny skonstruowany przykład S {} jest wywoływana w przypadku.
W rzeczywistości tak nie jest. Kolejność w [dcl.init.list] jest:
Lista inicjalizacja obiektu lub odniesienia typu T jest zdefiniowany następująco:
- Jeśli T jest agregat klasa a lista inicjator ma pojedynczy element typu cv U, [...]
- W przeciwnym razie, jeśli T jest tablicą znaków i [...]
- W przeciwnym razie, jeśli T jest agregatem, przeprowadzana jest inicjalizacja agregacyjna (8.6.1).
Po usunięciu konstruktora S(void *)
, S
staje agregatem - nie ma konstruktora użytkownika warunkiem. S() = default
nie jest liczony jako dostarczony przez użytkownika z przyczyn. Inicjalizacja agregacji z {}
zakończy się inicjowaniem wartości elementu i
.
Dlaczego konstruktor konwersja ma wyższy priorytet niż domyślny w pierwszym przypadku?
Z void*
pozostałego, trzymajmy zejście listę wypunktowania:
- W przeciwnym wypadku, gdy lista inicjator ma żadnych elementów [...]
- W przeciwnym razie, jeśli T jest specjalizacja z std :: initializer_list, [...]
- W przeciwnym razie, jeśli T jest typem klasy, rozważane są konstruktorzy. Odpowiednie konstruktory są wymienione na , a najlepsze wybiera się poprzez rozdzielczość przeciążenia (13.3, 13.3.1.7).
[over.match.list] daje dwufazowej Proces rozwiązywania przeciążeniowe
- początkowo funkcje kandydujące inicjatora-lista konstruktory (8.6.4) listy argumentów klasy T i składa się z listy inicjalizatorów jako pojedynczego argumentu.
- Jeśli nie zostanie znaleziony wykonalny konstruktor listy inicjalizującej, ponownie zostanie wykonana rezerwa przeciążania, gdzie funkcje kandydujące są wszystkie konstruktorami klasy T, a lista argumentów składa się z elementów z listy inicjalizatora.
Jeśli na liście inicjalizacyjnej nie ma elementów, a znak T ma domyślny konstruktor, pominięto pierwszą fazę.
S
nie ma żadnych initializer lista konstruktorów, więc idziemy do drugiej kuli i wyliczyć wszystkie konstruktorów z listy argument {}
. Mamy wiele żywotnych konstruktory:
S(S const&);
S(S&&);
S(void *);
Sekwencje konwersji są zdefiniowane w [over.ics.list]
przeciwnym razie, jeśli nie jest parametrem kruszywa klasy X i przeciążenie rozdzielczości na 13,3 .1.7 wybiera pojedynczego najlepszego konstruktora C z X, aby wykonać inicjalizację obiektu typu X z listy inicjalizatora argumentów:
- Jeśli C nie jest konstruktorem listy inicjalizacyjnej, a lista inicjalizacyjna ma pojedynczy element typu cv U, [...] - W przeciwnym razie niejawna sekwencja konwersji jest zdefiniowana przez użytkownika sekwencja konwersji z drugą standardową sekwencją konwersji i konwersja tożsamości.
i
W przeciwnym razie, jeśli typ parametru nie jest klasą: [...] - jeśli lista inicjator ma elementy, niejawna konwersja sekwencja jest konwersja tożsamość.
Oznacza to, że konstruktorzy S(S&&)
i S(S const&)
są zarówno zdefiniowanymi przez użytkownika sekwencjami konwersji, jak i konwersją tożsamości. Ale S(void *)
to tylko konwersja tożsamości.
Ale [over.best.ics] ma tę dodatkową zasadę:
Jednakże, jeśli cel jest
- pierwszy parametr konstruktora lub
- niejawny parametr przedmiot zdefiniowana przez użytkownika funkcja konwersji i konstruktor lub zdefiniowana przez użytkownika funkcja konwersji jest kandydatem
- 13.3.1.3, gdy [...]
- 13.3.1.4, 13.3.1.5 lub 13.3.1.6 (we wszystkich przypadkach), lub
- druga faza 13.3.1.7 gdy lista inicjatora ma dokładnie jeden element, który sam nie jest lista inicjator, a celem jest pierwszym parametrem konstruktora klasy X
i konwersji do X
lub w odniesieniu do (Prawdopodobnie cv-kwalifikowany) X
,
zdefiniowane przez użytkownika sekwencje konwersji nie są brane pod uwagę.
Wyklucza to z uwagi S(S const&)
i S(S&&)
jako kandydaci - są to właśnie w tym przypadku - celem jest pierwszym parametrem konstruktora wyniku drugiego etapu [over.match.list] i cel będący odniesieniem do potencjalnie kwalifikowanego cv S
, a taka sekwencja konwersji byłaby zdefiniowana przez użytkownika.
Dlatego jedynym pozostałym kandydatem jest S(void *)
, więc jest to banalnie najlepszy kandydat.
"* Jeśli drugi konstruktor zostanie skomentowany, to S {{}} jest nadal poprawnym wyrażeniem, ale (na pewno) konstruktor ruchu z konstruowanej domyślnie instancji S {} jest wywoływany w przypadku. *" Nie , agreguje-inicjuje 'S' za pomocą polecenia brace-init'd' int'. – ildjarn
@ildjarn Pytanie wciąż obowiązuje. – Orient