Est-ce que créer un constructeur ayant plusieurs arguments explicit
a un effet (utile)?
Exemple:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Réponses:
Jusqu'au C ++ 11, oui, aucune raison d'utiliser explicit
sur un constructeur multi-arg.
Cela change dans C ++ 11, en raison des listes d'initialiseurs. Fondamentalement, l'initialisation de copie (mais pas l'initialisation directe) avec une liste d'initialiseurs 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
explicit
. Je ne prendrais pas personnellement la peine de créer des constructeurs multi-arg explicit
.
Vous tomberiez dessus pour l'initialisation d'accolades (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 en sont la principale raison. Cependant, à mon humble avis, cela a du sens (du moins je le fais), dans le cadre de la vérification future des modifications ultérieures du code. 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
, donc cela devient ceci:
class A {
public:
A( int b, int c=0 );
};
En faisant cela, vous vous concentrez sur le c
paramètre - rétrospectivement, il devrait avoir une valeur par défaut. Vous ne vous demandez pas nécessairement si A
elle-même doit être implicitement construite. Malheureusement, ce changement rend à explicit
nouveau pertinent.
Donc, pour faire comprendre qu'un ctor est explicit
, il pourrait être payant de le faire lors de la première écriture de la méthode.
explicit
qui existe depuis toujours, et le support technique sera inondé d'appels à propos de ce changement et passera des heures à expliquer que ce explicit
n'était que du bruit et que le supprimer est inoffensif. Personnellement, je ne suis pas très doué pour prédire l'avenir; il est assez difficile de décider quelle interface doit ressembler maintenant .
Voici mes cinq cents à 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 bar
fonction bac struct Bar
car le constructeur de est déclaré comme explicit
.