Я не розумію, чому це складається


80

У мене, звичайно, чогось не вистачає, але я не розумію, чому це компілюється (з обома g ++ та clang ++):

struct A
{
};
struct B
{
};

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

Перш за все, Bце тип ... а не значення. Як слід інтерпретувати цей код?



8
@alterigel Це справді? У цьому випадку неоднозначності немає. Це може бути лише оголошення функції. Це не те, A a(B());що могло б бути визначенням змінної або декларацією функції.
волоський горіх

8
Ви будете здивовані, дізнавшись, що struct A{}; int main() { A(foo); } компіляція є такою, яка є , навіть якщо fooнічого не називає.
Айксан

20
@alterigel - це не найприємніший розбір. Подивіться приклади на сторінці, на яку ви пов’язали. Це просто оголошення функції.
Піт Бекер

3
@ PeteBecker, може бути краще пояснити, чому це не MVP, а не просто стверджувати, що це не так, як я вважаю, горіх вже робив вище.
JPhi1618

Відповіді:


84

Це трактується як оголошення функції з назвою a, яка бере один аргумент типу Bі повертає A.


5
І саме тому це Most та Vexing. Рішення: (не те, що воно насправді вирішує щось, оскільки воно викриває погану конструкцію)A a{B};
user4581301

23
@ user4581301 - це не найприємніший розбір. Це просто оголошення функції.
Піт Бекер

23
Тож виявляється, що це лише в основному
розгульний

11
Частина дивною про це в тому , що C ++ не допускає вкладені функції, але це дозволяє декларацію всередині функції.
The_Sympathizer

6
Звучить як хороша мотивація для додавання підтримки до вкладених функцій у C ++; Вони не тільки були б корисними, але перетворили б цю дивну бородавку на розумний дизайн :)
Jeremy

15

Це просто декларація функції, яка оголошує aфункцію, що повертає Aта приймає один неназваний параметр типу B.

Це дійсно, оскільки декларації функції на відміну від визначень функцій дозволені в визначеннях функції.


13

Це питання відоме як найбільш роздратований аналіз . Рядок A a(B);може бути інтерпретований як оголошення функції, що називається aповерненням об'єкта типу Aта прийняттям неназваного параметра типу B.

Одним із способів уникнути цього питання є використання синтаксису рівномірного ініціалізації, який був введений у C ++ 11, який полягає у використанні дужок замість дужок: A a{B};повертає помилку. Тепер рядок інтерпретується як ініціалізація змінної, ініціалізована з B, яка є типом замість значення.

Ось додаткова інформація:

Самий розгульний аналіз: як його помітити і швидко виправити


12
Я не думаю, що це слід називати " найбільш розпусним розбором ". Це просто звичайне оголошення функції, як воно існує і в C. Немає необхідності двозначності, оскільки рядок може бути лише оголошенням функції, нічого іншого. Подивіться на своє посилання. Всі приклади відрізняються від цього.
волоський горіх

3
Хоча це правда, це пов’язано з самим неприємним розбором. Просто це також включало помилку помилки, де ім'я типу використовувалося самостійно замість змінної або виклику конструктора, як це було, мабуть, оригінальним наміром.
Miral

1
Так, "Most Vexing Parse" - корисна відповідь у цьому випадку, навіть якщо фактичний випадок у питанні - це лише "Злегка розбіжний розбір".
jpa

1
@wlanut: Порожні структури struct A { };недійсні в стандартному C, навіть якщо деякі компілятори дозволяють їх. Скиньте дужки, і там не виникне проблем. Крім того, у C, декларування або визначення struct Aне створює імені типу A(ви повинні встановити його префіксом structабо додати typedef struct A A;десь до того, як Aбуде використано без structпрефікса). Крім того, в C не існує альтернативного розбору оголошення функції - використання type name(...);просто ніколи не може бути змінним визначенням; це завжди оголошення функції (або недійсне). Код у питанні не дійсний у C.
Джонатан Леффлер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.