Чи має конструктор, що має кілька аргументів 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.