Явный конструктор, принимающий несколько аргументов


делает конструктор, имеющий несколько аргументов explicit есть ли (полезный) эффект?

пример:

class A {
    public:
        explicit A( int b, int c ); // does explicit have any (useful) effect?
};
4 54

4 ответа:

до C++11, Да, нет причин использовать explicit в конструкторе с несколькими аргументами.

это изменяется в 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

вы наткнетесь на него для инициализации скобки (например, в массивах)

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 являются основной причиной. Тем не менее, ИМХО, это имеет смысл (по крайней мере, я это делаю), как часть будущих проверок более поздних изменений в коде. Рассмотрим ваш пример:

class A {
    public:
        explicit A( int b, int c ); 
};

этот код напрямую не выигрывает от explicit.

некоторое время спустя, вы решили добавить значение по умолчанию для c, так получается вот что:

class A {
    public:
        A( int b, int c=0 ); 
};

делая это, вы фокусируетесь на c параметр-в ретроспективе, это должен иметь значение по умолчанию. Вы не обязательно фокусируетесь на Ли A само должно быть неявно построено. К сожалению, это изменение делает explicit снова актуальна.

Итак, чтобы передать, что ctor-это 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 функция bacause конструктор struct Bar объявлен explicit.