Como uma continuação interessante (embora não de grande importância prática) para minha pergunta anterior: Por que C ++ nos permite colocar o nome da variável entre parênteses ao declarar uma variável?
Eu descobri que combinar a declaração entre parênteses com o recurso de nome de classe injetado pode levar a resultados surpreendentes em relação ao comportamento do compilador.
Dê uma olhada no seguinte programa:
#include <iostream>
struct B
{
};
struct C
{
C (){ std::cout << "C" << '\n'; }
C (B *) { std::cout << "C (B *)" << '\n';}
};
B *y = nullptr;
int main()
{
C::C (y);
}
Compilar com g ++ 4.9.2 me dá o seguinte erro de compilação:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
Compila com sucesso com MSVC2013 / 2015 e imprime
C (B *)
Compila com sucesso com o clang 3.5 e imprime
C
Portanto, a pergunta obrigatória é: qual está certo? :)
(No entanto, mudei fortemente para a versão clang e a maneira do msvc de parar de declarar a variável depois de apenas alterar o tipo com tecnicamente seu typedef parece meio estranho)
fonte
C::C y;
não faz sentido, certo? Nem aC::C (y);
princípio, pensei que fosse uma instância de Most-Vexing-Parse stackoverflow.com/questions/tagged/most-vexing-parse , mas agora acho que é apenas um comportamento indefinido, o que significa que todos os três compiladores estão "certos".C::C
não nomeia um tipo, ele nomeia uma função, então o GCC está certo.Respostas:
O GCC está correto, pelo menos de acordo com as regras de pesquisa do C ++ 11. 3.4.3.1 [class.qual] / 2 especifica que, se o especificador de nome aninhado for o mesmo que o nome da classe, ele se refere ao construtor e não ao nome da classe injetada. Ele dá exemplos:
Parece que o MSVC o interpreta erroneamente como uma expressão de conversão de estilo de função, criando um temporário
C
comy
como um parâmetro do construtor; e o Clang o interpreta erroneamente como uma declaração de uma variável chamaday
de tipoC
.fonte
A::A a;
, os nomes das funções devem ser ignorados - ou não?C (B *)
" .G ++ está correto porque apresenta um erro. Porque o construtor não pode ser chamado diretamente nesse formato sem o
new
operador. E embora seu código chameC::C
, parece uma chamada de construtor. No entanto, de acordo com o padrão C ++ 11 3.4.3.1, esta não é uma chamada de função válida ou um nome de tipo ( consulte a resposta de Mike Seymour ).O Clang está errado, pois nem mesmo chama a função correta.
MSVC é algo razoável, mas ainda não segue o padrão.
fonte
new
operadora muda?new B(1,2,3)
é algum tipo de "chamada direta do construtor" (o que, claro, não é) diferente da instanciação temporáriaB(1,2,3)
ou da declaraçãoB b(1,2,3)
.new B(1,2,3)
é?new
, um nome de tipo e uma lista de argumentos do construtor. Ainda não é uma "chamada direta do construtor".C::C (y);
comoC::C y;
, ou seja, uma definição de uma variável y do tipo C (usando o tipo C injetado: : C enquanto ignora erroneamente a especificação cada vez mais insana da linguagem 3.4.1,2 que torna C :: C o construtor). Esse não é um erro gritante como você parece pensar, imo.