Czy tworzenie konstruktora z wieloma argumentami explicit
ma jakiś (użyteczny) efekt?
Przykład:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Odpowiedzi:
Aż do C ++ 11, tak, nie ma powodu, aby używać explicit
na konstruktorze z wieloma argumentami.
To się zmienia w C ++ 11 z powodu list inicjalizujących. Zasadniczo inicjalizacja kopiowania (ale nie inicjalizacja bezpośrednia) z listą inicjatorów wymaga, aby konstruktor nie był oznaczony explicit
.
Przykład:
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
. Osobiście nie zawracałbym sobie głowy tworzeniem konstruktorów wieloskładnikowych explicit
.
Natknąłbyś się na to podczas inicjalizacji nawiasów klamrowych (na przykład w tablicach)
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;
}
Głównym powodem są doskonałe odpowiedzi udzielone przez @StoryTeller i @Sneftel. Jednak IMHO, ma to sens (przynajmniej ja to robię), jako część przyszłego sprawdzania późniejszych zmian w kodzie. Rozważ swój przykład:
class A {
public:
explicit A( int b, int c );
};
Ten kod nie korzysta bezpośrednio z explicit
.
Jakiś czas później decydujesz się dodać domyślną wartość dla c
, więc staje się ona następująca:
class A {
public:
A( int b, int c=0 );
};
Robiąc to, koncentrujesz się na c
parametrze - z perspektywy czasu powinien on mieć wartość domyślną. Niekoniecznie koncentrujesz się na tym, czy A
sam powinien być skonstruowany w sposób niejawny. Niestety, ta zmiana explicit
znów ma znaczenie.
Tak więc, aby pokazać explicit
, że ctor jest , warto byłoby to zrobić podczas pierwszego pisania metody.
explicit
, co było tam od zawsze, a pomoc techniczna będzie zalewana wezwaniami na temat tej zmiany i spędzać godziny na wyjaśnianiu, że explicit
to tylko hałas, a usuwanie go jest nieszkodliwe. Osobiście nie jestem dobry w przepowiadaniu przyszłości; Trudno zdecydować, co na tyle interfejs powinien wyglądać teraz .
Oto moje pięć centów do tej dyskusji:
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;
}
Jak łatwo zauważyć, explicit
zapobiega używaniu listy inicjalizującej razem z bar
funkcją, ponieważ konstruktor struct Bar
jest zadeklarowany jako explicit
.