Nie rozumiem, dlaczego to się kompiluje

80

Z pewnością czegoś brakuje, ale nie rozumiem, dlaczego to się kompiluje (zarówno z g ++, jak i clang ++):

struct A
{
};
struct B
{
};

int main()
{
  A a(B);
}

Przede wszystkim Bjest typem ... a nie wartością. Jak mam interpretować ten kod?

Picaud Vincent
źródło
37
Jest to znane jako Najbardziej Vexing Parse
alter igel
8
@alterigel Czy to naprawdę? W tym przypadku nie ma dwuznaczności. Może to być tylko deklaracja funkcji. Nie jest A a(B());to definicja zmiennej lub deklaracja funkcji.
orzech
8
Byłbyś zaskoczony, wiedząc, że struct A{}; int main() { A(foo); } kompiluje się w obecnej postaci , nawet jeśli fooniczego nie wymienia.
Ayxan,
20
@alterigel - nie jest to najbardziej dokuczliwa analiza. Spójrz na przykłady na stronie, do której linkujesz. To jest po prostu deklaracja funkcji.
Pete Becker,
3
@ PeteBecker, może lepiej wyjaśnić, dlaczego nie jest to MVP, zamiast po prostu twierdzić, że nie jest, co, jak sądzę, orzech już zrobił powyżej.
JPhi1618,

Odpowiedzi:

84

Jest interpretowany jako deklaracja o nazwie funkcja a, która pobiera jeden argument typu Bi zwraca A.

Brian
źródło
5
I właśnie dlatego jest Most i Vexing. Rozwiązanie: (nie to, że faktycznie coś rozwiązuje, ponieważ ujawnia złą konstrukcję)A a{B};
user4581301
23
@ user4581301 - to nie najbardziej dokuczliwy parse. To po prostu deklaracja funkcji.
Pete Becker,
23
Tak więc okazuje się, że to tylko głównie dokuczliwy parse ...
MooseBoys
11
Najdziwniejsza część o tym, że C ++ nie zezwala funkcji zagnieżdżonych, ale nie pozwalają deklaracji wewnątrz funkcji.
The_Sympathizer,
6
Brzmi jak dobra motywacja do dodania obsługi zagnieżdżonych funkcji w C ++; nie tylko przydałyby się, zamieniłyby tę dziwną brodawkę w rozsądny projekt :)
Jeremy Friesner
15

Jest to po prostu deklaracja funkcji, która deklaruje, aże jest funkcją zwracającą Ai przyjmującą jeden nienazwany parametr typu B.

Jest poprawny, ponieważ deklaracje funkcji, w przeciwieństwie do definicji funkcji, są dozwolone w definicjach funkcji.

maszyna_1
źródło
13

Ten problem jest znany jako najbardziej dokuczliwa analiza . Linia A a(B);może być interpretowana jako deklaracja funkcji o nazwie azwracającej obiekt typu Ai przyjmującej nienazwany parametr typu B.

Jednym ze sposobów uniknięcia tego problemu jest użycie jednolitej składni inicjalizacji, która została wprowadzona w C ++ 11, która polega na użyciu nawiasów klamrowych zamiast nawiasów: A a{B};zwraca błąd. Linia jest teraz interpretowana jako inicjalizacja deklaracji zmiennej B, która jest typem zamiast wartości.

Oto więcej informacji:

Najbardziej zwariowana analiza: jak ją zlokalizować i szybko naprawić

G. Morin
źródło
12
Nie sądzę, że należy to nazwać „ najbardziej dokuczliwą analizą ”. Jest to zwykła deklaracja funkcji, ponieważ istnieje ona również w C. Nie ma potrzeby rozwiązywania niejednoznaczności, ponieważ wiersz może być tylko deklaracją funkcji, niczym więcej. Spójrz na swój link. Wszystkie przykłady różnią się od tego.
orzech
3
Chociaż to prawda, jest to związane z najbardziej dokuczliwą analizą. Tyle, że zawierało to także literówkę, w której nazwa typu została użyta sama zamiast zmiennej lub wywołania konstruktora, jak zapewne pierwotna intencja.
Miral
1
Tak, „Most Vexing Parse” jest przydatną odpowiedzią w tym przypadku, nawet jeśli faktyczny przypadek w pytaniu to po prostu „Slightly Vexing Parse”.
jpa
1
@wlanut: Puste struktury struct A { };nie są poprawne w standardowym C, nawet jeśli niektóre kompilatory na to pozwalają. Upuść szelki, a tam nie będzie problemu. Również w C deklarowanie lub definiowanie struct Anie tworzy nazwy typu A(musisz ją poprzedzić structlub dodać typedef struct A A;gdzieś przed Aużyciem bez structprefiksu). Również w C nie ma alternatywnej analizy względem deklaracji funkcji - użycie type name(...);po prostu nigdy nie może być definicją zmiennej; zawsze jest to deklaracja funkcji (lub niepoprawna). Kod w pytaniu jest nieprawidłowy w C.
Jonathan Leffler,