Круглые скобки в C ++ используются во многих местах: например, в вызовах функций и выражениях группировки для переопределения приоритета операторов. Помимо недопустимых дополнительных круглых скобок (например, вокруг списков аргументов вызова функций), общее, но не абсолютное правило C ++ состоит в том, что лишние круглые скобки никогда не повредят :
5.1 Первичные выражения [expr.prim]
5.1.1 Общие [expr.prim.general]
6 Выражение в скобках - это первичное выражение, тип и значение которого идентичны таковым в заключенном выражении. Наличие круглых скобок не влияет на то, является ли выражение значением l. Выражение в скобках может использоваться в тех же контекстах, что и заключенное в него выражение, и с тем же значением, если не указано иное .
Вопрос : в каких контекстах дополнительные круглые скобки изменяют смысл программы на C ++, кроме отмены приоритета базовых операторов?
ПРИМЕЧАНИЕ . Я считаю, что ограничение синтаксиса указателя на член&qualified-id
без круглых скобок выходит за рамки области применения, поскольку оно ограничивает синтаксис, а не позволяет использовать два синтаксиса с разными значениями. Точно так же использование круглых скобок внутри определений макросов препроцессора также защищает от нежелательного приоритета оператора.
источник
&(C::f)
, операнд&
по - прежнемуC::f
, не так ли?expr.unary.op/4
: указатель на член формируется только тогда, когда используется явное указание,&
а его операнд представляет собой квалифицированный идентификатор, не заключенный в круглые скобки.()
над селектором указателя на член::*
Ответы:
TL; DR
Дополнительные круглые скобки изменяют значение программы на C ++ в следующих контекстах:
decltype
выраженияхПредотвращение поиска имени, зависящего от аргумента
Как подробно описано в Приложении A к Стандарту, a
post-fix expression
формы(expression)
- это aprimary expression
, но неid-expression
, и, следовательно, неunqualified-id
. Это означает, что поиск имени, зависящий от аргументов, предотвращается при вызовах функций формы(fun)(arg)
по сравнению с обычной формойfun(arg)
.3.4.2 Поиск имени в зависимости от аргумента [basic.lookup.argdep]
namespace N { struct S { }; void f(S); } void g() { N::S s; f(s); // OK: calls N::f (f)(s); // error: N::f not considered; parentheses // prevent argument-dependent lookup }
Включение оператора запятой в контекстах списка
Оператор запятая имеет особое значение в большинстве контекстов, подобных списку (аргументы функции и шаблона, списки инициализаторов и т. Д.). Скобки формы
a, (b, c), d
в таких контекстах могут включать оператор запятой по сравнению с обычной формой,a, b, c, d
где оператор запятой не применяется.5.18 Оператор запятой [expr.comma]
f(a, (t=3, t+2), c);
Разрешение неоднозначности неприятных синтаксических разборов
Обратная совместимость с C и его загадочным синтаксисом объявления функций может привести к неожиданным двусмысленностям синтаксического анализа, известным как досадный синтаксический анализ. По сути, все, что может быть проанализировано как объявление, будет анализироваться как одно , даже если конкурирующий синтаксический анализ также будет применяться.
6.8 Разрешение неоднозначности [stmt.ambig]
8.2 Разрешение неоднозначности [dcl.ambig.res]
struct S { S(int); }; void foo(double a) { S w(int(a)); // function declaration S x(int()); // function declaration S y((int)a); // object declaration S z = int(a); // object declaration }
Известным примером этого является Most Vexing Parse , имя, популяризированное Скоттом Мейерсом в пункте 6 его книги Effective STL :
ifstream dataFile("ints.dat"); list<int> data(istream_iterator<int>(dataFile), // warning! this doesn't do istream_iterator<int>()); // what you think it does
Это объявляет функцию,
data
возвращаемый тип которойlist<int>
. Данные функции принимают два параметра:dataFile
. Это типа естьistream_iterator<int>
. Круглые скобкиdataFile
излишни и игнорируются.istream_iterator<int>
.Добавление дополнительных круглых скобок вокруг первого аргумента функции (круглые скобки вокруг второго аргумента недопустимы) устранит двусмысленность
list<int> data((istream_iterator<int>(dataFile)), // note new parens istream_iterator<int>()); // around first argument // to list's constructor
C ++ 11 имеет синтаксис инициализатора фигурных скобок, который позволяет обходить такие проблемы синтаксического анализа во многих контекстах.
Выведение референсов в
decltype
выраженияхВ отличие от
auto
вывода типов,decltype
позволяет выводить ссылки (ссылки lvalue и rvalue). Правила различатьdecltype(e)
иdecltype((e))
выражения:7.1.6.2 Спецификаторы простого типа [dcl.type.simple]
const int&& foo(); int i; struct A { double x; }; const A* a = new A(); decltype(foo()) x1 = 0; // type is const int&& decltype(i) x2; // type is int decltype(a->x) x3; // type is double decltype((a->x)) x4 = x3; // type is const double&
Правила для
decltype(auto)
имеют аналогичное значение для дополнительных круглых скобок в правой части инициализирующего выражения. Вот пример из FAQ C ++ и связанных вопросов и ответовdecltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; } //A decltype(auto) look_up_a_string_2() { auto str = lookup1(); return(str); } //B
Первый возвращается
string
, второй возвращаетсяstring &
, что является ссылкой на локальную переменнуюstr
.Предотвращение ошибок, связанных с макросами препроцессора
При взаимодействии макросов препроцессора с самим языком C ++ существует множество тонкостей, наиболее распространенные из которых перечислены ниже.
#define TIMES(A, B) (A) * (B);
, чтобы избежать нежелательного приоритета оператора (например, вTIMES(1 + 2, 2 + 1)
котором дает 9, но дает 6 без скобок вокруг(A)
и(B)
assert((std::is_same<int, int>::value));
которые иначе не компилируются(min)(a, b)
(с нежелательным побочным эффектом также отключение ADL)источник
if
/,while
если выражение является присваиванием. Напримерif (a = b)
- предупреждение (вы имели в виду==
?), Аif ((a = b))
- без предупреждения.(min)(a, b)
(со злым МАКРОСОМmin(A, B)
) частью предотвращения поиска имени, зависящего от аргументов?Как правило, в языках программирования «лишние» скобки означают, что они не меняют порядок синтаксического анализа или значение. Они добавляются для уточнения порядка (приоритета операторов) в интересах людей, читающих код, и их единственный эффект будет заключаться в небольшом замедлении процесса компиляции и уменьшении человеческих ошибок при понимании кода (возможно, ускорение общего процесса разработки. ).
Если набор круглых скобок действительно меняет способ анализа выражения, то они по определению не являются дополнительными. Скобки, которые превращают незаконный / недействительный синтаксический анализ в допустимый, не являются «лишними», хотя это может указывать на плохой языковой дизайн.
источник