Fazer um construtor com vários argumentos explicit
tem algum efeito (útil)?
Exemplo:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Respostas:
Até C ++ 11, sim, não há razão para usar explicit
em um construtor multi-arg.
Isso muda no C ++ 11, por causa das listas de inicializadores. Basicamente, a inicialização de cópia (mas não a inicialização direta) com uma lista de inicializadores requer que o construtor não seja marcado explicit
.
Exemplo:
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
. Eu pessoalmente não me incomodaria em fazer construtores multi-arg explicit
.
Você tropeçaria nele para a inicialização da chave (por exemplo, em matrizes)
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;
}
As excelentes respostas de @StoryTeller e @Sneftel são o principal motivo. No entanto, IMHO, isso faz sentido (pelo menos eu faço isso), como parte da verificação futura de alterações posteriores no código. Considere seu exemplo:
class A {
public:
explicit A( int b, int c );
};
Este código não se beneficia diretamente de explicit
.
Algum tempo depois, você decide adicionar um valor padrão para c
, então ele se torna este:
class A {
public:
A( int b, int c=0 );
};
Ao fazer isso, você está se concentrando no c
parâmetro - em retrospecto, ele deve ter um valor padrão. Você não está necessariamente focando se A
ele deve ser construído implicitamente. Infelizmente, essa mudança torna explicit
relevante novamente.
Portanto, para transmitir que um ctor é explicit
, pode valer a pena fazê-lo ao escrever o método pela primeira vez.
explicit
que está lá há muito tempo, e o suporte técnico será inundado com ligações sobre essa mudança e passará horas explicando que explicit
era apenas ruído e que removê-lo é inofensivo. Pessoalmente, não sou muito bom em prever o futuro; já é difícil decidir como uma interface deve ser agora .
Aqui estão meus cinco centavos para esta discussão:
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 você pode ver facilmente, explicit
evita o uso da lista de inicializadores juntamente com a bar
função porque o construtor de struct Bar
é declarado como explicit
.