Чому C ++ дозволяє нам оголошувати ім'я змінної в дужках при оголошенні змінної?


84

Наприклад декларація типу:

int (x) = 0;

Або навіть це:

int (((x))) = 0;

Я натрапив на це, тому що в моєму коді у мене трапився фрагмент, подібний до наступного:

struct B
{
};

struct C
{
  C (B *) {}
  void f () {};
};

int main()
{
  B *y;
  C (y);
}

Очевидно, я хотів побудувати об'єкт, Cякий потім зробив би щось корисне у своєму деструкторі. Однак, як це трапляється, компілятор трактує C (y);як оголошення змінної yз типом Cі, таким чином, друкує помилку про yперевизначення. Цікаво, що якщо я напишу це як C (y).f ()або щось подібне, C (static_cast<B*> (y))воно буде скомпільоване за призначенням. Найкраще сучасне обхідне рішення, звичайно, використовувати {}у виклику конструктора.

Отже, як я зрозумів після цього, можна оголосити змінні як int (x) = 0;або навіть, int (((x))) = 0;але я ніколи не бачив, щоб хтось насправді використовував такі оголошення. Отже, мене цікавить - яка мета такої можливості, оскільки на даний момент я бачу, що вона створює лише випадок, подібний до горезвісного "найбільш неприємного розбору", і не додає нічого корисного?


"Мета" можливості - це, мабуть, спростити парсер.
молбдніло


1
@GSerg Забавно, як текст мого запитання відповідає на запитання з другої відповіді у вашому зв’язаному питанні, оскільки я наводжу приклад, коли дозволення таких декларацій призводить до несподіваних результатів :)
Предельник


зайшов у цю пастку: не знав, що мьютекс коментували, а потім випадково написав неправильну декларацію в дужках. // std :: mutex std :: unique_lock <std :: mutex> (m_mutex);
Подавати Лауріссену

Відповіді:


80

Групування.

Як окремий приклад, розглянемо, що ви можете оголосити змінну типу функції, таку як

int f(int);

Тепер, як би ви оголосили вказівник на таке?

int *f(int);

Ні, не працює! Це трактується як повернення функції int*. Вам потрібно додати в дужки, щоб зробити його синтаксичний аналіз правильним чином:

int (*f)(int);

Те саме стосується масивів:

int *x[5];   // array of five int*
int (*x)[5]; // pointer to array of five int

13
І щоб завершити відповідь: заборона на конкретний випадок, про який запитує запитувач, потребує додаткового правила для особливого випадку. Поточне визначення того, як ()робота в типі є однаковою для всього типу.
Джозеф Менсфілд,

Отож, особливий випадок застосовується до найбільш дратівливого розбору. Це тому, що синтаксис для ініціалізації змінних за допомогою аргументів конструктора був доданий пізніше (напевно, поспішаючи?).
AnArrayOfFunctions

1
@FISOCPP Ну. . так. C ++ з’явився після C.. .
iheanyi

Чи однаково ця відповідь стосується С, а не лише С ++?
kdbanman

" змінна типу функції " що? !!
curiousguy

17

Як правило, у таких оголошеннях дозволяється використовувати дужки, оскільки декларація з синтаксичної точки зору завжди виглядає так:

<front type> <specification>;

Наприклад, у такій декларації:

int* p[2];

"Фронтальний тип" - це int(не int*), а "специфікація" - це * p[2].

Правило полягає в тому, що ви можете використовувати будь-яку кількість дужок, як це потрібно в частині "специфікації", оскільки їх іноді неминуче роз'єднати. Наприклад:

int* p[2]; // array of 2 pointers to int; same as int (*p[2]);
int (*p)[2]; // pointer to an array of 2 ints

Вказівник на масив - це рідкісний випадок, проте така ж ситуація, як і у випадку з покажчиком для функціонування:

int (*func(int)); // declares a function returning int*
int (*func)(int); // declares a pointer to function returning int

Це пряма відповідь на ваше запитання. Якщо ваше питання стосується твердження типу C(y), тоді:

  • Поставте дужки навколо всього виразу - (C(y))і ви отримаєте те, що хотіли
  • Цей вислів не робить нічого, крім створення тимчасового об'єкта, який перестає жити після закінчення цієї інструкції (сподіваюся, це те, що ви мали намір зробити).

1
Як я вже згадував, спочатку він робив щось у деструкторі, я думаю, це досить стандартна річ, коли у вас є деяка кількість "ланцюгових" функцій для встановлення деяких параметрів, а потім виконує всю роботу в деструкторі. Дякую за ще одне обхідне рішення, однак, я думаю, що написання {}є найбільш дійсним, зрештою.
Предельник

4
намагайтеся уникати складання власної граматики та використовуйте ту, що передбачена стандартом. <front-type> <specification>вводить в оману і неправильно. Граматика така<declaration-specifier> <declarator>
Стів Кокс

Ви маєте рацію - я не заглядав у стандарт, просто повторював правило з голови. Насправді в C ++ 11 роль також <declaration-specifier>може виконувати autoключове слово, тому це навіть не завжди тип.
Ethouris,

@Pravasi Meet: Якщо ви відредагували частину мого допису та змінили імена у даній схемі синтаксису, будь-ласка, відповідно змініть імена на 3 рядки нижче. В іншому випадку все ще існують старі назви "тип спереду" та "специфікація", і тому публікація не має жодного сенсу.
Ethouris
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.