Costruttore esplicito che accetta più argomenti


88

Creare un costruttore con più argomenti explicitha qualche effetto (utile)?

Esempio:

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

Risposte:


120

Fino a C ++ 11, sì, non c'è motivo di usarlo explicitsu un costruttore multi-argomento.

Ciò cambia in C ++ 11, a causa degli elenchi di inizializzatori. Fondamentalmente, l'inizializzazione della copia (ma non l'inizializzazione diretta) con un elenco di inizializzatori richiede che il costruttore non sia contrassegnato explicit.

Esempio:

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

5
Penso che questa risposta sarebbe migliore con la spiegazione "Perché dovrei volerlo" o "Quando è utile".
MateuszL

@MateuszL La risposta di Edgar offre probabilmente il miglior argomento del perché potrebbe essere utile (e probabilmente merita il segno di spunta). Il motivo per cui è , però, è semplicemente perché è l'estensione logica della semantica esistente per explicit. Personalmente non mi preoccuperei di creare costruttori multi-argomento explicit.
Sneftel

31

Ci si imbatte in esso per l'inizializzazione delle parentesi graffe (ad esempio negli array)

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;
}

24

Le ottime risposte di @StoryTeller e @Sneftel sono il motivo principale. Tuttavia, IMHO, questo ha senso (almeno lo faccio), come parte della verifica futura delle modifiche successive al codice. Considera il tuo esempio:

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

Questo codice non beneficia direttamente di explicit.

Qualche tempo dopo, decidi di aggiungere un valore predefinito per c, quindi diventa questo:

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

Quando lo fai, ti stai concentrando sul cparametro: in retrospettiva, dovrebbe avere un valore predefinito. Non ti stai necessariamente concentrando sul fatto che se Astesso debba essere costruito implicitamente. Sfortunatamente, questa modifica è di explicitnuovo rilevante.

Quindi, per comunicare che un ctor è explicit, potrebbe essere utile farlo quando si scrive per la prima volta il metodo.


Ma che dire del caso in cui il manutentore aggiunge quel valore predefinito e conclude che il risultato dovrebbe essere disponibile come costruttore di conversione? Ora devono rimuovere ciò explicitche è lì da sempre e il supporto tecnico sarà inondato di chiamate su quel cambiamento e passerà ore a spiegare che explicitera solo rumore e che rimuoverlo è innocuo. Personalmente, non sono molto bravo a predire il futuro; è già abbastanza difficile decidere come dovrebbe apparire un'interfaccia ora .
Pete Becker

@PeteBecker Questo è un buon punto. Personalmente penso che i due casi siano asimmetrici e che sia molto più comune quando si impostano i parametri predefiniti (o li si rimuove) inavvertitamente rendere la classe implicitamente costruibile, per poi rendersi effettivamente conto allo stesso tempo che in retrospettiva dovrebbe essere così. Detto questo, queste sono considerazioni "morbide" e potrebbero variare tra persone / progetti / ecc., O anche solo una questione di gusti.
Ami Tavory

8

Ecco i miei cinque centesimi per questa discussione:

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;
}

Come puoi facilmente vedere, explicitimpedisce di usare la lista degli inizializzatori insieme alla barfunzione perché il costruttore di struct Barè dichiarato come explicit.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.