c++ - smart - Propósito de constructores predeterminados explícitos
smart contracts ethereum (1)
Esto declara un constructor por defecto explícito:
struct A {
explicit A(int a1 = 0);
};
A a = 0; /* not allowed */
A b; /* allowed */
A c(0); /* allowed */
En caso de que no haya ningún parámetro, como en el siguiente ejemplo, el explicit
es redundante.
struct A {
/* explicit is redundant. */
explicit A();
};
En algún borrador de C ++ 0x (creo que era n3035), hizo la diferencia de la siguiente manera:
A a = {}; /* error! */
A b{}; /* alright */
void function(A a);
void f() { function({}); /* error! */ }
Pero en la FCD, cambiaron esto (aunque, sospecho que no tenían esta razón en particular en mente) en que los tres casos inicializan con valor el objeto respectivo. La inicialización del valor no hace el baile de resolución de sobrecarga y, por lo tanto, no fallará en los constructores explícitos.
Recientemente noté una clase en C ++ 0x que requiere un constructor predeterminado explícito. Sin embargo, no estoy logrando un escenario en el que un constructor predeterminado pueda ser llamado implícitamente. Parece un especificador bastante inútil. Pensé que tal vez no permitiría la Class c;
a favor de la Class c = Class();
pero ese no parece ser el caso.
Algunas citas relevantes del C ++ 0x FCD, ya que para mí es más fácil navegar [texto similar existe en C ++ 03, si no en los mismos lugares]
12.3.1.3 [class.conv.ctor]
Un constructor predeterminado puede ser un constructor explícito; dicho constructor se utilizará para realizar la inicialización predeterminada o la inicialización de valores (8.5).
Continúa para proporcionar un ejemplo de un constructor predeterminado explícito, pero simplemente imita el ejemplo que proporcioné anteriormente.
8.5.6 [decl.init]
Para inicializar por defecto un objeto de tipo T significa:
- si T es un tipo de clase (posiblemente cv calificado) (Cláusula 9), se llama al constructor predeterminado para T (y la inicialización está mal formada si T no tiene un constructor por defecto accesible);
8.5.7 [decl.init]
Para inicializar con valor un objeto de tipo T significa:
- si T es un tipo de clase (posiblemente cv calificado) (Cláusula 9) con un constructor proporcionado por el usuario (12.1), entonces se llama al constructor predeterminado para T (y la inicialización está mal formada si T no tiene un constructor predeterminado accesible) );
En ambos casos, el estándar requiere que se llame al constructor predeterminado. Pero eso es lo que sucedería si el constructor predeterminado no fuera explícito. Para el bien de la compleción:
8.5.11 [decl.init]
Si no se especifica un inicializador para un objeto, el objeto se inicializa por defecto;
Por lo que puedo decir, esto solo deja la conversión de no datos. Lo cual no tiene sentido. Lo mejor que se me ocurre sería lo siguiente:
void function(Class c);
int main() {
function(); //implicitly convert from no parameter to a single parameter
}
Pero obviamente esa no es la forma en que C ++ maneja los argumentos por defecto. ¿Qué más hay que haría explicit Class();
comportarse de manera diferente de la Class();
?
El ejemplo específico que generó esta pregunta fue std::function
[20.8.14.2 func.wrap.func]. Requiere varios constructores de conversión, ninguno de los cuales está marcado como explícito, pero el constructor predeterminado es.