2010-05-14 11 views
27

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 Class c; a favor de Class c = Class();, pero ese no parece ser el caso.Propósito de constructores predeterminados explícitos

Algunas citas relevantes de la C++ 0x FCD, ya que es más fácil para mí para navegar [existe un texto similar 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 usará para realizar inicialización por defecto o inicialización de valor (8.5).

Sigue proporcionando un ejemplo de un constructor predeterminado explícito, pero simplemente imita el ejemplo que proporcioné anteriormente.

8.5.6 [decl.init]

Para default-inicializar un objeto de tipo T significa:

- si T es un tipo de clase (posiblemente cv-cualificada) (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 valor-inicializar un objeto de tipo T significa:

- si T es un tipo de clase (posiblemente cv-cualificada) (cláusula 9) con una constructor provisto 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 por defecto 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. Por el bien integridad:

8.5.11 [decl.init]

Si no se especifica el inicializador para un objeto, el objeto es default-inicializado;

Por lo que puedo decir, esto simplemente deja la conversión sin datos. Lo cual no tiene sentido. Lo mejor que puedo llegar a sería el siguiente:

void function(Class c); 
int main() { 
    function(); //implicitly convert from no parameter to a single parameter 
} 

Pero obviamente eso no es la forma en C++ maneja los argumentos por defecto. ¿Qué más hay que haga que explicit Class(); se comporte de manera diferente a 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.

+0

Tan pronto como llegue a la publicación, creo que se me ocurrió una explicación. Pero esperaré la confirmación de mis sospechas, ya que parece una pregunta útil de todos modos. –

Respuesta

21

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 hay ningún parámetro, como en el siguiente ejemplo, el explicit es redundante.

struct A { 
    /* explicit is redundant. */ 
    explicit A(); 
}; 

En algunos proyectos de C++ 0x, creo que fue n3035, que hizo una diferencia en la forma siguiente:

A a = {}; /* error! */ 
A b{}; /* alright */ 

void function(A a); 
void f() { function({}); /* error! */ } 

Pero en el FCD, que changed this (aunque, sospecho que no tenían en cuenta esta razón en particular) porque los tres casos valorizan el objeto respectivo. La inicialización del valor no realiza el baile de resolución de sobrecarga y, por lo tanto, no fallará en los constructores explícitos.

+0

Bien. Entonces, ¿el constructor explícito para 'std :: function' es simplemente una retención de esa versión del borrador? Fue esta explicación la que finalmente descubrí después de escribir la pregunta, pero ni el ejemplo proporcionado ni 'std :: function()' tomaron un parámetro opcional, por lo que no estaba completamente convencido. –

+0

Esto parece haber cambiado un poco, ver [CWG 1518] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1518). Las versiones recientes de g ++ y clang ++ rechazan 'function ({})' para constructores predeterminados explícitos no predeterminados, incluso en el modo C++ 11. – dyp

+0

Véase también http://cplusplus.github.io/LWG/lwg-defects.html#2510 –

Cuestiones relacionadas