template c++ c++11 initializer-list explicit-constructor in-class-initialization

template - C++ 11: la inicialización en clase con "={}" no funciona con el constructor explícito



using en c++ (3)

En C ++ 11 podemos hacer una inicialización en clase usando un "inicializador de corsé o igual" (palabras del estándar) como esto:

struct Foo { /*explicit*/ Foo(int) {} }; struct Bar { Foo foo = { 42 }; };

Pero si no hacemos comentarios explicit , ya no se compila. GCC 4.7 y 4.9 dicen esto:

error: converting to ‘Foo’ from initializer list would use explicit constructor ‘Foo::Foo(int)’

Me pareció sorprendente. ¿Es realmente la intención del estándar C ++ 11 que este código no compila?

Eliminando el = arregla: Foo foo { 42 }; pero personalmente me parece más difícil de explicar a las personas que han estado acostumbradas a la forma con = durante décadas, y dado que el estándar se refiere a un "inicializador de paréntesis", no es obvio por qué la buena manera antigua no funciona. en este escenario.


widget w = {x};

Esto se denomina “inicialización de la lista de copias”. Significa lo mismo que el widget w {x}; excepto que no se pueden usar constructores explícitos. Se garantiza que solo se llama a un único constructor.

De http://herbsutter.com/2013/05/09/gotw-1-solution/

Consulte el resto del artículo para obtener una discusión más detallada sobre las diversas formas en que puede inicializar un objeto.


No puedo explicar la razón detrás de esto, pero puedo repetir lo obvio.

Me pareció sorprendente. ¿Es realmente la intención del estándar C ++ 11 que este código no compila?

§13.3.1.7

En copy-list-initialization, si se elige un constructor explícito, la inicialización está mal formada.

Eliminando el = lo arregla: Foo foo { 42 }; pero personalmente me parece más difícil de explicar a las personas que han estado acostumbradas a la forma con = durante décadas, y dado que el estándar se refiere a un "inicializador de paréntesis", no es obvio por qué la buena manera antigua no funciona. en este escenario.

Foo foo { 42 } es la inicialización directa , mientras que el signo igual (con llaves) hace que sea copy-list-initialization . Otra respuesta explica que debido a que la compilación falla en copy-initialization de la copy-initialization (signo igual sin llaves), no debería sorprender que también falle en la inicialización de la lista de la copia, pero las dos fallan por razones diferentes.

cppreference:

La inicialización directa es más permisiva que la inicialización de copia: la inicialización de copia solo considera constructores no explícitos y funciones de conversión definidas por el usuario, mientras que la inicialización directa considera a todos los constructores y secuencias de conversión implícitas.

Y su página en el especificador explícito :

Especifica constructores y (desde C ++ 11) operadores de conversión que no permiten conversiones implícitas o inicialización de copias.

Por otro lado, para copiar-lista-inicialización:

Objeto T = { arg1 , arg2 , ... }; (10)

10) en el lado derecho del signo igual (similar a la inicialización de la copia)

  • De lo contrario, los constructores de T se consideran, en dos fases:

    • Si la etapa anterior no produce una coincidencia, todos los constructores de T participan en la resolución de sobrecarga contra el conjunto de argumentos que consta de los elementos de la lista-iniciada, con la restricción de que solo se permiten conversiones no limitantes. Si esta etapa produce un constructor explícito como la mejor coincidencia para una inicialización de lista de copias, la compilación falla (nota, en la simple inicialización de copias, los constructores explícitos no se consideran en absoluto)

Como se discutió en ¿Qué podría salir mal si la inicialización de la lista de copias permitiera constructores explícitos? , la compilación falla porque el constructor explícito está seleccionado pero no se permite su uso.


Si Foo(int) es explicit , entonces esto no compilará también:

Foo foo = 42;

Así que para "las personas que han estado acostumbradas a la forma con = durante décadas" no será una sorpresa que la forma con {} tampoco compile.