Чи має конструктор, що має кілька аргументів explicit
, якийсь (корисний) ефект?
Приклад:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Відповіді:
Аж до C ++ 11, так, немає жодних причин для використання explicit
на конструкторі multi-arg.
Це змінюється в C ++ 11 через списки ініціалізаторів. В основному, для ініціалізації копіювання (але не прямої ініціалізації) зі списком ініціалізаторів потрібно, щоб конструктор не був позначений explicit
.
Приклад:
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
. Я б особисто не заважав створювати конструктори з декількома аргументами explicit
.
Ви натрапите на нього для ініціалізації фігурних дужок (наприклад, у масивах)
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;
}
Відмінні відповіді @StoryTeller та @Sneftel - головна причина. Однак, IMHO, це має сенс (принаймні я це роблю), оскільки частина майбутніх перевірок згодом змінює код. Розглянемо ваш приклад:
class A {
public:
explicit A( int b, int c );
};
Цей код безпосередньо не виграє explicit
.
Через деякий час ви вирішили додати значення за замовчуванням для c
, тож воно стає таким:
class A {
public:
A( int b, int c=0 );
};
Роблячи це, ви орієнтуєтесь на c
параметр - ретроспективно він повинен мати значення за замовчуванням. Ви не обов’язково концентруєтеся на тому, чи A
слід самому будуватись неявно. На жаль, ця зміна explicit
знову робить актуальним.
Отже, щоб донести, що це ктор explicit
, може заробити це зробити при першому написанні методу.
explicit
що було там назавжди, а технічна підтримка буде завалена дзвінками про цю зміну і годинами пояснюватиме, що це explicit
був просто шум, і що його видалення нешкідливо. Особисто я не дуже добре передбачаю майбутнє; досить важко вирішити, яким повинен бути інтерфейс зараз .
Ось мої п’ять центів до цієї дискусії:
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;
}
Як ви можете легко побачити, explicit
заважає використовувати список ініціалізаторів разом із bar
функцією, оскільки конструктор з struct Bar
оголошено як explicit
.