Например, такое объявление:
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;
но я никогда не видел, чтобы кто-то действительно использовал такие объявления. Так что меня интересует - в чем цель такой возможности, потому что пока я вижу, что это только создает случай, похожий на пресловутый «самый неприятный синтаксический анализ», и не добавляет ничего полезного?
источник
Ответы:
Группировка.
В качестве конкретного примера рассмотрим, что вы можете объявить переменную типа функции, например
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
источник
()
работать с типом, едино для всего типа.Обычно в таких объявлениях разрешается использовать круглые скобки, потому что объявление с синтаксической точки зрения всегда выглядит так:
Например, в следующем объявлении:
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))
и вы получите то, что хотелиисточник
{}
в конце концов является наиболее подходящим.<front-type> <specification>
вводит в заблуждение и неверно. Грамматика<declaration-specifier> <declarator>
<declaration-specifier>
может также игратьauto
ключевое слово, так что это даже не всегда тип.