Como “int main () {(([] () {}) ());}” é válido em C ++?

271

Recentemente, deparei com o seguinte código esotérico.

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

Reformate-o da seguinte forma para torná-lo mais legível:

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

Mas não consigo entender como (([](){})())é um código válido.

  • Não parece com a sintaxe do ponteiro de função.
  • Não pode ser um truque de sobrecarga do operador. O código compila como está.

O Google não ajudou muito nessa pesquisa com todos os símbolos. Mas ele compila no Visual Studio 2010 e não produz nada. Não houve erros nem avisos. Portanto, parece um código válido.

Eu nunca vi qualquer código válido que está fora de forma bizarra de JavaScript e C ponteiros de função .

Alguém pode explicar como isso é válido em C ++?

Mysticial
fonte
94
Ei! Isso é meu. "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (9 de novembro no chat)
veja
31
É um fechamento lambda do c ++ 11
7
@Mysticial - Este código o confunde porque é inútil. Se esse lambda fizesse algo, você o reconheceria com uma sintaxe semelhante aos ponteiros de função (com os quais está intimamente relacionado).
SChepurin
14
@Mysticial - "6 years of C ++" - lambdas foram adicionadas no C ++ 11, então ninguém tem experiência com elas antes de um ano ou mais atrás.
Pete Becker #
50
O URL aqui é muito divertido: "como-é-int main-valid-c"
tckmn

Respostas:

283

O código essencialmente chama uma lambda vazia.

Vamos começar do começo: [](){}é uma expressão lambda vazia .

Então, em C e C ++, você pode envolver expressões em parênteses e eles se comportam exatamente da mesma como se fosse escrito sem eles, então é isso que o primeiro par de parênteses em torno da lambda faz. Estamos agora em ([](){}).

Então, ()após o primeiro empacotamento, o parens chama o lambda (vazio). Estamos agora em([](){})()

Toda a expressão está envolta em parênteses novamente e entendemos (([](){})()).

Por fim, ;termina a declaração. Chegamos a (([](){})());.


† Existem alguns casos de canto pelo menos em C ++, como T a_var; há uma diferença entre decltype(a_var)edecltype((a_var)) .

Xeo
fonte
7
Perdeu uma adaga.
R. Martinho Fernandes
33
@ R.MartinhoFernandes: Ainda estava preso em alguém, então tive que ir buscá-lo.
Xeo 28/11
1
Eu ia votar por mencionar corretamente o caso em que adicionar () em torno de uma expressão altera a semântica. Mas então lembrei que, na verdade, não tem relação com a questão. Boa resposta
sehe
2
Os parênteses também estão mudando o significado de um programa no caso da desambiguação de análise mais irritante: B foo(A())foo é uma função (pegar um ponteiro para funcionar como único parâmetro e retornar um B) enquanto em B foo((A()))foo é um objeto B construído invocando um construtor a Um objeto (cuja instância é temporária anônima neste caso).
Anúncio N
1
@ AdN: Isso não é mais uma expressão, mas uma declaração.
Xeo 23/08/13