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