Conversioni implicite in C ++

Diversi commenti su una mia recente risposta, Quali altri cast utili possono essere usati in C ++ , suggeriscono che la mia comprensione delle conversioni C ++ è errata. Giusto per chiarire il problema, considera il seguente codice:

#include  struct A { A( const std::string & s ) {} }; void func( const A & a ) { } int main() { func( "one" ); // error func( A("two") ); // ok func( std::string("three") ); // ok } 

La mia affermazione è stata che la prima chiamata di funzione è un errore, perché non vi è alcuna conversione da un const char * a un A. Esiste una conversione da una stringa ad una A, ma l’utilizzo di questo implicherebbe più di una conversione. La mia comprensione è che questo non è permesso, e questo sembra essere confermato da g ++ 4.4.0 e compilatori Comeau. Con Comeau, ottengo il seguente errore:

 "ComeauTest.c", line 11: error: no suitable constructor exists to convert from "const char [4]" to "A" func( "one" ); // error 

Se puoi indicare, dove ho torto, qui o nella risposta originale, preferibilmente con riferimento allo standard C ++, per favore fallo.

E la risposta dallo standard C ++ sembra essere:

Al massimo una conversione definita dall’utente (funzione di costruzione o conversione) viene implicitamente applicata a un singolo valore.

Grazie ad Abhay per aver fornito la citazione.

Penso che la risposta di Sharptooth sia precisa. La sezione 12.3.4 dello standard C ++ (SC22-N-4411.pdf) intitolata “Conversioni” chiarisce che è consentita solo una conversione implicita definita dall’utente.

1 Le conversioni di tipi di oggetti di class possono essere specificate dai costruttori e dalle funzioni di conversione. Queste conversioni sono chiamate conversioni definite dall’utente e sono utilizzate per conversioni di tipo implicito (clausola 4), per l’inizializzazione (8.5) e per conversioni di tipo esplicito (5.4, 5.2.9).

2 Le conversioni definite dall’utente sono applicate solo dove non sono ambigue (10.2, 12.3.2). Le conversioni obbediscono alle regole di controllo degli accessi (Clausola 11). Il controllo di accesso viene applicato dopo la risoluzione di ambiguità (3.4).

3 [Nota: vedere 13.3 per una discussione sull’uso delle conversioni nelle chiamate di funzione e negli esempi di seguito. -End note]

4 Al massimo una conversione definita dall’utente (funzione di costruzione o conversione) viene implicitamente applicata a un singolo valore.

Come sembra essere già il consenso: sì hai ragione.

Ma poiché questa domanda / risposta diventerà probabilmente il punto di riferimento per le conversioni implicite in C ++ su StackOverflow, vorrei aggiungere che per gli argomenti del modello le regole sono diverse.

Non sono consentite conversioni implicite per gli argomenti utilizzati per la deduzione degli argomenti del modello. Questo potrebbe sembrare abbastanza ovvio, ma tuttavia può portare a sottili stranezze.

Caso in questione, std :: operatori di aggiunta di stringhe

  std::string s; s += 67; // (1) s = s + 67; // (2) 

(1) compila e funziona bene, operator+= è una funzione membro, il parametro carattere template è già dedotto dall’istanza di std::string per s (in char ). Le conversioni implicite sono consentite ( int -> char ), i risultati in s contengono l’equivalente char di 67, ad esempio in ASCII questo diventerebbe ‘C’

(2) dà un errore del compilatore come operator+ è dichiarato come una funzione libera e qui l’argomento del carattere del template è usato in deduzione.

È vero, è consentita solo una conversione implicita .

Due conversioni di fila possono essere eseguite con una combinazione di un operatore di conversione e un costruttore parametrizzato, ma ciò provoca un avviso C4927 – “conversione illegale, più di una conversione definita dall’utente è stata implicitamente applicata” – in VC ++ per un motivo.

Il linguaggio di programmazione C ++ (4 ° ed.) (Sezione 18.4.3) dice che

solo un livello di conversione implicita definita dall’utente è legale

Quella parte “definita dall’utente” fa sembrare che possano essere consentite più conversioni implicite se alcune sono tra tipi nativi.