c++ - ¿Error del compilador(conocido) en VC12?
visual-c++ visual-studio-2013 (2)
Parece que Visual Studio
simplemente está roto con respecto a qué constructor llama cuando el argumento predeterminado es una lista de inicializadores . Este código:
#include <iostream>
struct test {
test () { std::cout << "test ()" << std::endl ; }
test (int) { std::cout << "test (int)" << std::endl ; }
};
void func( test const &s = {} )
{
}
int main()
{
test s = {} ;
func() ;
}
produce este resultado en gcc
y clang
, clang
en vivo aquí :
test ()
test ()
mientras que Visual Studio
produce este resultado:
test ()
test (int)
y para este código:
#include <iostream>
#include <initializer_list>
struct test {
test () { std::cout << "test ()" << std::endl ; };
test (int) { std::cout << "test (int)" << std::endl ; };
test ( std::initializer_list<int>) { std::cout << "test (initializer_list<int>)" << std::endl ; } ;
};
void func( test const &s = {0} )
{
}
int main()
{
test s = {0} ;
func() ;
}
gcc
y clang
producen este resultado, véalo en vivo aquí :
test (initializer_list<int>)
test (initializer_list<int>)
mientras Visual Studio
produce este error:
error C2440: ''default argument'' : cannot convert from ''initializer-list'' to ''const test &''
Reason: cannot convert from ''initializer-list'' to ''const test''
No constructor could take the source type, or constructor overload resolution was ambiguous
Actualizar
Para un control de cordura, volví al estándar para asegurarme de que no había una regla extraña en la raíz de esta diferencia o tal vez alguna restricción que hace que este código esté mal formado . Por lo que puedo decir, este código no está mal formado . La sección 8.3.5
gramática permite específicamente esto:
parameter-declaration:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
[...]
No parece que los Iniciales de la sección 8.5
o los argumentos predeterminados de 8.3.6
agreguen ninguna restricción, pero este informe de defectos es 994. braced-init-list como argumento predeterminado y documento de trabajo La redacción de los paréntesis iniciales como argumentos predeterminados deja en claro que fue intencionado y describa los cambios realizados en el estándar para permitirlo y al observar los deltas no hay restricciones obvias.
Este programa, cuando se compila con VC12 (en Visual Studio 2013 RTM) [1] provoca un bloqueo (en todas las configuraciones de compilación), cuando en realidad no debería:
#include <string>
void foo(std::string const& oops = {})
{
}
int main()
{
foo();
}
Sé de dos errores silenciosos de codegen que podrían estar relacionados:
- https://connect.microsoft.com/VisualStudio/feedback/details/800364/initializer-list-calls-object-destructor-twice
- http://connect.microsoft.com/VisualStudio/feedback/details/800104/
Honestamente, creo que estos son diferentes, sin embargo. Alguien sabe
- si hay un error activamente rastreado en connect para esto
- si hay una solución alternativa (o una descripción explícita de la situación que causa este error, para que podamos buscarlo / evitarlo en nuestra base de código)?
[1] Solo crea un proyecto vacío usando el ''asistente'' de la aplicación de consola C ++. Para simplificar, deshabilite los encabezados precompilados y deje todos los valores predeterminados: http://i.stack.imgur.com/rrrnV.png
Un problema activo fue publicado en connect.microsoft.com/VisualStudio/feedback/details/809243/… . El código de muestra publicado fue:
Compile and run following code in VS2013
#include <string>
void f(std::string s = {}) {
}
int main(int argc, char* argv[]) {
f();
return 0;
}
El error ha sido reconocido por Microsoft.
No parece haber una solución temporal publicada allí. Editar soluciones se puede basar fácilmente en evitar la sintaxis del inicializador de listas:
void f(std::string s = "");
void f(std::string s = std::string());
void f(std::string s = std::string {});
O simplemente a la antigua (si no le importa introducir sobrecargas):
void f(std::string s);
void f() { f(std::string()); }