Constructor explícito que toma múltiples argumentos

88

¿Hacer un constructor que tenga múltiples argumentos explicittiene algún efecto (útil)?

Ejemplo:

class A {
    public:
        explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Peter G.
fuente

Respuestas:

120

Hasta C ++ 11, sí, no hay razón para usarlo expliciten un constructor de múltiples argumentos.

Eso cambia en C ++ 11, debido a las listas de inicializadores. Básicamente, la inicialización de la copia (pero no la inicialización directa) con una lista de inicializadores requiere que el constructor no esté marcado explicit.

Ejemplo:

struct Foo { Foo(int, int); };
struct Bar { explicit Bar(int, int); };

Foo f1(1, 1); // ok
Foo f2 {1, 1}; // ok
Foo f3 = {1, 1}; // ok

Bar b1(1, 1); // ok
Bar b2 {1, 1}; // ok
Bar b3 = {1, 1}; // NOT OKAY
Sneftel
fuente
5
Creo que esta respuesta sería mejor con una explicación de "¿Por qué querría eso?" O "¿Cuándo es útil?".
MateuszL
@MateuszL La respuesta de Edgar es probablemente el mejor argumento de por qué podría ser útil (y podría decirse que merece la marca). Sin embargo, la razón por la que está ahí es simplemente porque es la extensión lógica de la semántica existente para explicit. Personalmente, no me molestaría en hacer constructores de múltiples argumentos explicit.
Sneftel
31

Se toparía con él para la inicialización de llaves (por ejemplo, en matrices)

struct A {
        explicit A( int b, int c ) {}
};

struct B {
         B( int b, int c ) {}
};

int main() {
    B b[] = {{1,2}, {3,5}}; // OK

    A a1[] = {A{1,2}, A{3,4}}; // OK

    A a2[] = {{1,2}, {3,4}}; // Error

    return 0;
}
StoryTeller - Unslander Monica
fuente
24

Las excelentes respuestas de @StoryTeller y @Sneftel son la razón principal. Sin embargo, en mi humilde opinión, esto tiene sentido (al menos yo lo hago), como parte de futuras pruebas de cambios posteriores al código. Considere su ejemplo:

class A {
    public:
        explicit A( int b, int c ); 
};

Este código no se beneficia directamente de explicit.

Algún tiempo después, decide agregar un valor predeterminado para c, por lo que se convierte en esto:

class A {
    public:
        A( int b, int c=0 ); 
};

Al hacer esto, se está enfocando en el cparámetro; en retrospectiva, debería tener un valor predeterminado. No se está enfocando necesariamente en si Adebe construirse implícitamente. Lamentablemente, este cambio vuelve a explicitser relevante.

Entonces, para transmitir que un ctor es explicit, podría ser útil hacerlo al escribir el método por primera vez.

Ami Tavory
fuente
Pero, ¿qué pasa con el caso en el que el mantenedor agrega ese valor predeterminado y concluye que el resultado debería estar disponible como un constructor de conversión? Ahora tienen que eliminar lo que explicitha estado allí desde siempre, y el soporte técnico se verá inundado de llamadas sobre ese cambio y pasará horas explicando que explicites solo ruido y que eliminarlo es inofensivo. Personalmente, no soy muy bueno para predecir el futuro; Ya es bastante difícil decidir cómo debería verse una interfaz ahora .
Pete Becker
@PeteBecker Ese es un buen punto. Personalmente, creo que los dos casos son asimétricos, y que es mucho más común al hacer que los parámetros sean predeterminados (o eliminarlos) inadvertidamente hacer que la clase sea implícitamente construible, y luego darse cuenta al mismo tiempo que en retrospectiva debería haber sido así. Dicho esto, estas son consideraciones "suaves" y pueden variar entre personas / proyectos / etc., O incluso simplemente ser una cuestión de gustos.
Ami Tavory
8

Aquí están mis cinco centavos para esta discusión:

struct Foo {
    Foo(int, double) {}
};

struct Bar {
    explicit Bar(int, double) {}
};

void foo(const Foo&) {}
void bar(const Bar&) {}

int main(int argc, char * argv[]) {
    foo({ 42, 42.42 }); // valid
    bar({ 42, 42.42 }); // invalid
    return 0;
}

Como puede ver fácilmente, explicitevita el uso de la lista de inicializadores junto con la barfunción porque el constructor de struct Barse declara como explicit.

Edgar Rokjān
fuente