Почему и как лишние скобки изменяют тип выражения в C++ (C++11)?

При каких обстоятельствах дополнительные группирующие скобки нарушают работу C++ (в частности, C++11)? По причинам, которые здесь не имеют значения, в какой-то момент я столкнулся с выражением, вокруг которого был дополнительный, ненужный набор скобок, и я обнаружил, что функция typeinfo C++11 is_same определяет, что это другой тип, чем тот же код без скобок. Вот упрощённый пример несколько непонятного поведения:

#include <iostream>
using namespace std;

int main()
{
  string s = "foo";
  cout << std::is_same<decltype(s), decltype(string("foo"))>::value;
  cout << std::is_same<decltype(s), decltype((s))>::value;
  cout << std::is_same<decltype((s)), decltype(string("foo"))>::value;
  cout << std::is_same<decltype((s)+"x"), decltype(string("foo")+"x")>::value;

  return 0;
}

Этот код печатает «1001», что, по-видимому, указывает на то, что лишние скобки в двух средних строках приводят к тому, что выражение имеет другой тип, но использование этого выражения в скобках в более крупном выражении снова делает его того же типа. С другой стороны, если я использую typeid для получения имени типа, typeid(s) и typeid((s)), кажется, производят одно и то же.

Теперь я работал над непосредственной проблемой, но я до сих пор не понимаю, почему это происходит в первую очередь; Поиск «двойных скобок С++» и т.п., похоже, не дает ничего подходящего (в основном страницы о перегрузке операторов и расширениях компилятора, которые активируются только после определенного ключевого слова).

Итак: что, черт возьми, здесь происходит? Почему тип s отличается от типа (s)?


person blahedo    schedule 02.02.2014    source источник
comment
Существует специальное правило для decltype, которое применяется, если выражение внутри скобок decltype является выражением-идентификатором или доступом-членом-класса. Добавление второй пары скобок делает его основным-выражением (но само не является выражением-идентификатором или доступом-членом-класса), поэтому специальное правило не применяется. См., например, stackoverflow.com/q/14115744/420683 или stackoverflow.com/q/3097779/420683   -  person dyp    schedule 03.02.2014
comment
Кроме того, foo((1, 2)); имеет другое значение, чем foo(1, 2);. Это вопрос вообще про скобки или про decltype?   -  person dyp    schedule 03.02.2014
comment
Скобки также могут иметь значение при применении унарного &: struct foo { int m; void bar() { auto x = &foo::bar; auto y = &(foo::bar); } }; Здесь x относится к типу int (foo::*), тогда как y относится к типу int*. Но это не относится к С++ 11.   -  person dyp    schedule 03.02.2014
comment
@dyp Насчет последнего: я думаю, вы имеете в виду foo::m, а не foo::bar.   -  person    schedule 03.02.2014
comment
@hvd Ой, конечно. Слишком поздно исправлять :( Живой пример (с исправлением).   -  person dyp    schedule 03.02.2014
comment
Кажется, ссылка @dyp на stackoverflow.com/q/3097779/420683 содержит ответ. См., например. ideone.com/FqrcEy, так что decltype(s) дает string, а decltype((s)) становится string &.   -  person NonNumeric    schedule 03.02.2014
comment
@dyp, не могли бы вы объяснить свой пример foo(1,2)? Или вы имели в виду (foo)(1,2), отключающий ADL?   -  person TemplateRex    schedule 03.02.2014
comment
@TemplateRex foo((1,2)) — это вызов функции только с одним выражением аргумента, а именно (1,2) — это один аргумент со значением 2. И отключение ADL — еще один хороший пример, когда скобки имеют значение :)   -  person dyp    schedule 03.02.2014


Ответы (1)


decltype обрабатывает свои аргументы по-разному в зависимости от дополнительных круглых скобок.

Вторая пара круглых скобок делает его основным выражением (но не само выражением id или доступом к члену класса), поэтому специальное правило не применяется.

Вот обсуждение: Значение скобок в decltype((c))?

person Sergey K.    schedule 03.02.2014