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

Имеет ли конструктор с несколькими аргументами explicit какой-либо (полезный) эффект?

Пример:

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

person Peter G.    schedule 24.08.2016    source источник


Ответы (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
person Sneftel    schedule 24.08.2016
comment
Я думаю, что этот ответ был бы лучше: «Зачем мне это нужно» или «Когда это полезное объяснение». - person MateuszL; 10.05.2019
comment
@MateuszL Ответ Эдгара, вероятно, лучший аргумент в пользу того, почему он может быть полезен (и, возможно, заслуживает отметки). Причина, по которой он там, заключается просто в том, что это логическое расширение существующей семантики для explicit. Я бы лично не стал беспокоиться о создании конструкторов с несколькими аргументами explicit. - person Sneftel; 08.06.2020

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

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;
}
person StoryTeller - Unslander Monica    schedule 24.08.2016

Отличные ответы @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 актуальным.

Итак, чтобы передать, что ctor explicit, это может быть платным при первом написании метода.

person Ami Tavory    schedule 24.08.2016
comment
Но как насчет случая, когда сопровождающий добавляет это значение по умолчанию и приходит к выводу, что результат должен быть доступен как конструктор преобразования? Теперь им нужно удалить тот explicit, который был там всегда, и техническая поддержка будет завалена звонками по поводу этого изменения и потратит часы, объясняя, что explicit был просто шумом, и что удаление это безвредно. Лично я не очень хорошо умею предсказывать будущее; Достаточно сложно решить, как должен выглядеть интерфейс сейчас. - person Pete Becker; 24.08.2016
comment
@PeteBecker Это хорошее замечание. Я лично считаю, что эти два случая асимметричны, и что гораздо чаще при настройке параметров по умолчанию (или их удалении) непреднамеренно сделать класс неявно конструируемым, а затем в то же время фактически осознать, что в ретроспективе так и должно быть. При этом это мягкие соображения, которые могут варьироваться между людьми / проектами / и т. Д., Или даже быть просто делом вкуса. - person Ami Tavory; 24.08.2016

Вот мои пять центов за это обсуждение:

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.

person Edgar Rokjān    schedule 24.08.2016