Entre as muitas coisas que o Stack Overflow me ensinou é o que é conhecido como a "análise mais irritante", que é demonstrada classicamente com uma linha como
A a(B()); //declares a function
Enquanto isso, para a maioria, parece intuitivamente ser a declaração de um objeto a
do tipo A
, pegando um B
objeto temporário como parâmetro construtor, na verdade é uma declaração de uma função a
retornando um A
, levando um ponteiro para uma função que retorna B
e não aceita parâmetros . Da mesma forma a linha
A a(); //declares a function
também se enquadra na mesma categoria, pois, em vez de um objeto, declara uma função. Agora, no primeiro caso, a solução usual para esse problema é adicionar um conjunto extra de colchetes / parênteses ao redor do B()
, pois o compilador o interpretará como a declaração de um objeto
A a((B())); //declares an object
No entanto, no segundo caso, fazer o mesmo leva a um erro de compilação
A a(()); //compile error
Minha pergunta é por que? Sim, eu estou muito ciente de que a 'solução alternativa' correta é alterá-la para A a;
, mas estou curioso para saber o que o extra ()
faz para o compilador no primeiro exemplo, que depois não funciona ao aplicá-lo novamente. o segundo exemplo. A A a((B()));
solução alternativa é uma exceção específica gravada no padrão?
(B())
é apenas uma expressão C ++, nada mais. Não é nenhum tipo de exceção. A única diferença que faz é que não há como ele ser analisado como um tipo e, portanto, não é.A a();
é da mesma categoria. Para o compilador , nunca há uma maneira diferente de analisá-lo: um inicializador nesse local nunca consiste em parênteses vazios; portanto, essa é sempre uma declaração de função.A a();
não é um exemplo da análise mais irritante . É simplesmente uma declaração de função, assim como é em C.A a;
" está errado. Isso não lhe dará a inicialização de um tipo de POD. Para obter a inicialização, escrevaA a{};
.Respostas:
Não há resposta esclarecida, é apenas porque ela não é definida como sintaxe válida pela linguagem C ++ ... Por isso é assim, por definição da linguagem.
Se você tiver uma expressão dentro dela, ela é válida. Por exemplo:
Ainda mais simples: porque
(x)
é uma expressão C ++ válida, enquanto()
não é.Para aprender mais sobre como as línguas são definidas e como os compiladores funcionam, você deve aprender sobre a teoria formal da linguagem ou, mais especificamente, Gramáticas Livres de Contexto (CFG) e material relacionado, como máquinas de estados finitos. Se você estiver interessado nisso, embora as páginas da Wikipedia não sejam suficientes, você terá que adquirir um livro.
fonte
(x)
é uma expressão C ++ válida, enquanto()
não é.A solução final para esse problema é mudar para a sintaxe de inicialização uniforme C + 11, se possível.
http://www.stroustrup.com/C++11FAQ.html#uniform-init
fonte
Declaradores de função C
Primeiro de tudo, há C. Em C,
A a()
há declaração de função. Por exemplo,putchar
tem a seguinte declaração. Normalmente, essas declarações são armazenadas nos arquivos de cabeçalho; no entanto, nada impede que você as escreva manualmente, se você souber como é a declaração da função. Os nomes dos argumentos são opcionais nas declarações, então eu o omiti neste exemplo.Isso permite que você escreva o código assim.
C também permite definir funções que aceitam funções como argumentos, com uma sintaxe legível que se parece com uma chamada de função (bem, é legível, desde que você não retorne um ponteiro para a função).
Como eu mencionei, C permite omitir nomes de argumentos nos arquivos de cabeçalho, portanto,
output_result
ficaria assim no arquivo de cabeçalho.Um argumento no construtor
Você não reconhece esse? Bem, deixe-me lembrá-lo.
Sim, é exatamente a mesma declaração de função.
A
éint
,a
éoutput_result
eB
éint
.Você pode perceber facilmente um conflito de C com novos recursos do C ++. Para ser exato, construtores sendo o nome da classe e parênteses, e sintaxe de declaração alternativa com em
()
vez de=
. Por design, o C ++ tenta ser compatível com o código C e, portanto, precisa lidar com esse caso - mesmo que praticamente ninguém se importe. Portanto, os recursos antigos do C têm prioridade sobre os novos recursos do C ++. A gramática das declarações tenta corresponder o nome como função, antes de reverter para a nova sintaxe()
se ela falhar.Se um desses recursos não existisse ou tivesse uma sintaxe diferente (como
{}
no C ++ 11), esse problema nunca teria acontecido para a sintaxe com um argumento.Agora você pode perguntar por que
A a((B()))
funciona. Bem, vamos declararoutput_result
com parênteses inúteis.Isso não vai funcionar. A gramática requer que a variável não esteja entre parênteses.
No entanto, C ++ espera expressão padrão aqui. Em C ++, você pode escrever o seguinte código.
E o seguinte código.
O C ++ espera que a expressão dentro dos parênteses seja ... bem ... expressão, em oposição ao tipo C espera. Parênteses não significam nada aqui. No entanto, inserindo parênteses inúteis, a declaração da função C não é correspondida e a nova sintaxe pode ser correspondida corretamente (o que simplesmente espera uma expressão, como
2 + 2
).Mais argumentos no construtor
Certamente um argumento é bom, mas e dois? Não é que os construtores possam ter apenas um argumento. Uma das classes internas que recebe dois argumentos é
std::string
Está tudo bem (tecnicamente, teria a análise mais irritante se fosse escrita como
std::string wat(int(), char())
, mas sejamos honestos - quem escreveria isso? Mas vamos assumir que esse código tenha um problema irritante. Você supõe que deve colocar tudo entre parênteses.Não é bem assim.
Não sei por que o g ++ tenta converter
char
paraconst char *
. De qualquer maneira, o construtor foi chamado com apenas um valor do tipochar
. Não há sobrecarga que tenha um argumento do tipochar
, portanto, o compilador está confuso. Você pode perguntar - por que o argumento é do tipo char?Sim,
,
aqui está um operador de vírgula. O operador de vírgula recebe dois argumentos e fornece o argumento do lado direito. Não é realmente útil, mas é algo a ser conhecido pela minha explicação.Em vez disso, para resolver a análise mais irritante, é necessário o seguinte código.
Os argumentos estão entre parênteses, não a expressão inteira. De fato, apenas uma das expressões precisa estar entre parênteses, pois é suficiente interromper um pouco a gramática C para usar o recurso C ++. As coisas nos levam ao ponto de zero argumentos.
Zero argumento no construtor
Você pode ter notado a
eighty_four
função na minha explicação.Sim, isso também é afetado pela análise mais irritante. É uma definição válida e provavelmente você já viu se criou arquivos de cabeçalho (e deveria). Adicionar parênteses não o corrige.
Por que? Bem,
()
não é uma expressão. No C ++, você deve colocar uma expressão entre parênteses. Você não pode escreverauto value = ()
em C ++, porque()
isso não significa nada (e mesmo que isso significasse, como tupla vazia (consulte Python), seria um argumento, não zero). Na prática, isso significa que você não pode usar a sintaxe abreviada sem usar a{}
sintaxe do C ++ 11 , pois não há expressões entre parênteses e a gramática C para declarações de função sempre será aplicada.fonte
Você poderia
usar
fonte
int a = int();
inicializaa
com 0,int a;
deixaa
não inicializado. Uma solução correta é usarA a = {};
para agregados,A a;
quando a inicialização padrão faz o que você deseja eA a = A();
em todos os outros casos - ou apenas usa de formaA a = A();
consistente. No C ++ 11, basta usarA a {};
O parênteses mais interno no seu exemplo seria uma expressão e, em C ++, a gramática define um
expression
para ser umassignment-expression
ou outroexpression
seguido por vírgula e outroassignment-expression
(Apêndice A.4 - Resumo / expressões gramaticais).A gramática define ainda
assignment-expression
como um dos vários outros tipos de expressão, nenhum dos quais pode ser nada (ou apenas espaço em branco).Portanto, a razão pela qual você não pode ter
A a(())
é simplesmente porque a gramática não permite. No entanto, não sei responder por que as pessoas que criaram C ++ não permitiram esse uso específico de parênteses vazias como algum tipo de caso especial - eu acho que eles preferem não colocar em um caso tão especial se houver uma alternativa razoável.fonte