Как «int main () {(([] () {}) ());}» является допустимым C ++?

271

Недавно я наткнулся на следующий эзотерический фрагмент кода.

int main(){(([](){})());}

Переформатируйте его следующим образом, чтобы сделать его более читабельным:

int main(){
    (([](){})());   //  Um... what?!?!
}

Но я не могу понять, как (([](){})())действует код.

  • Это не похоже на синтаксис указателя функции.
  • Это не может быть какой-то уловкой перегрузки оператора. Код компилируется как есть.

Google не сильно помог с этим поиском по всем символам. Но он компилируется в Visual Studio 2010 и ничего не выводит. Не было ни ошибок, ни предупреждений. Так что похоже на действительный код.

Я никогда не видел какого - либо действительного кода , который так странно за пределами Javascript и C указателей функций .

Может кто-нибудь объяснить, как это действует C ++?

Mysticial
источник
94
Привет! Это мое. "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (9 ноября в чате)
2012 г.
31
это лямбда-закрытие c ++ 11
7
@Mysticial - этот код озадачивает вас, потому что он бесполезен. Если бы эта лямбда-то что-то делала, вы бы узнали, что ее синтаксис похож на указатели на функции (с которыми она тесно связана).
Щепурин
14
@Mysticial - "6 лет C ++" - лямбды были только что добавлены в C ++ 11, поэтому никто не имел опыта работы с ними до года или около того назад.
Пит Беккер
50
URL здесь довольно забавный: "how-is-int-main-valid-c"
tckmn

Ответы:

283

Код по сути вызывает пустую лямбду.

Начнем с самого начала: [](){}это пустое лямбда-выражение .

Тогда, в C и C ++, вы можете обернуть выражения в круглых скобках , и они ведут себя точно так же , как если бы написано без них, так это то, что первая пара скобок вокруг лямбды делает. Мы теперь в ([](){}).

Затем ()после первой обертки Паренс вызывает (пустую) лямбду. Мы сейчас в([](){})()

Все выражение снова оборачивается в парен, и мы получаем (([](){})()).

Наконец, ;заканчивается утверждение. Мы приходим к (([](){})());.


† Есть несколько угловых случаев, по крайней мере, в C ++, например, с T a_var; разницей между decltype(a_var)иdecltype((a_var)) .

Xeo
источник
7
Пропустил кинжал.
Р. Мартиньо Фернандес
33
@ R.MartinhoFernandes: Он все еще застрял в ком-то, поэтому мне пришлось пойти и найти его.
Xeo
1
Я собирался поддержать голосование за правильное упоминание случая, когда добавление () вокруг выражения изменяет семантику. Но потом я вспомнил, что это не имеет отношения к вопросу, на самом деле. Хороший ответ
сехе
2
Скобки также меняют смысл программы в случае наиболее неприятного устранения неоднозначности: B foo(A())foo - это функция (принимает указатель на функцию в качестве единственного параметра и возвращает B), тогда как в B foo((A()))foo создается объект B, вызывающий конструктор, принимающий Объект (который в данном случае является анонимным временным).
Объявление N
1
@AdN: это уже не выражение, а декларация.
Xeo