web-dev-qa-db-fra.com

Constructeur explicite prenant plusieurs arguments

Faire un constructeur ayant plusieurs arguments explicit a-t-il un effet (utile)?

Exemple:

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

Jusqu'à C++ 11, oui, aucune raison d'utiliser explicit sur un constructeur multi-arguments.

Cela change en C++ 11, à cause des listes d'initialisation. Fondamentalement, la copie-initialisation (mais pas l'initialisation directe) avec une liste d'initialisation nécessite que le constructeur ne soit pas marqué explicit.

Exemple:

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
101
Sneftel

Vous tomberiez dessus pour l'initialisation de l'accolade (par exemple dans les tableaux)

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;
}
27
StoryTeller

Les excellentes réponses de @StoryTeller et @Sneftel sont la principale raison. Cependant, à mon humble avis, cela a du sens (du moins je le fais), dans le cadre des modifications ultérieures apportées au code ultérieurement. Considérez votre exemple:

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

Ce code ne bénéficie pas directement de explicit.

Quelque temps plus tard, vous décidez d'ajouter une valeur par défaut pour c, cela devient donc ceci:

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

En faisant cela, vous vous concentrez sur le paramètre c - rétrospectivement, il devrait avoir une valeur par défaut. Vous ne vous concentrez pas nécessairement sur la question de savoir si A lui-même doit être implicitement construit. Malheureusement, cette modification rend à nouveau explicit pertinent.

Donc, pour indiquer qu'un ctor est explicit, il peut être avantageux de le faire lors de la première écriture de la méthode.

23
Ami Tavory

Voici mes cinq cents pour cette discussion:

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;
}

Comme vous pouvez facilement le voir, explicit empêche d'utiliser la liste d'initialisation avec la fonction bar parce que le constructeur de struct Bar est déclaré comme explicit.

6
Edgar Rokjān