perché il seguente codice non viene compilato e quando rimuovo la parola chiave esplicita prima del costruttore in classe A, viene compilato?Influenza dei costruttori "espliciti" nella risoluzione di sovraccarico
Utilizzando Visual Studio 2013:
enum E { e1_0, e1_1 };
template<typename T>
struct A
{
A() {}
explicit A(unsigned long) {}
A(T) {}
};
struct B
{
B() {}
B(E) {}
};
void F(B) {};
void F(A<short>) {};
void test()
{
F(e1_0);
}
Errore:
1>------ Build started: Project: exp_construct_test, Configuration: Debug Win32 ------
1> exp_construct_test.cpp
1>e:\exp_construct_test\exp_construct_test.cpp(23): error C2668: 'F' : ambiguous call to overloaded function
1> e:\exp_construct_test\exp_construct_test.cpp(19): could be 'void F(A<short>)'
1> e:\exp_construct_test\exp_construct_test.cpp(18): or 'void F(B)'
1> while trying to match the argument list '(E)'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Edit: Ho scaricato clang clang e compilato con-cl, che segnala l'errore per entrambi i casi. Quindi, come è stato sottolineato nei commenti, l'ambiguità è compresa tra A<short>(short)
e B(E)
.
Così, forse, c'è un bug in VC++, che quando rimuovo explicit
dal A(unsigned long)
, il compilatore con qualsiasi intenzione sceglie B (E) invece di generare un errore ambiguouity. Qualcuno può confermare il comportamento clang come standard compatibile e VC++ come bug?
ho aggiunto
void G(E) {};
void G(short) {};
e una chiamata a G come questo:
G(e1_0);
che non solleva alcun errore. Perché qui G(E)
è prefferrato e, in caso di candidati A<short>::A(short)
e B::B(E)
, sono ambigui?
Fine Edit
Grazie --joja
Se rimuovo 'explicit', non viene compilato neanche, il che non dovrebbe essere. La chiamata ambigua non è per 'A :: A' ma per' F'. Nota che 'A :: A (T)' non è 'esplicito' quindi la chiamata a' F' è ambigua. Se tu * aggiungi * un 'esplicito' a' A :: A (T) 'governerà la conversione e il codice verrà compilato, comunque. – 5gon12eder
La parola chiave esplicita di fronte a un costruttore impedisce l'istanza di un oggetto di quel tipo implicitamente con solo un parametro che agisce come un argomento costruttore. Quando rimuovi "esplicito" dal costruttore di A, puoi costruire A semplicemente passando "void F (A)" a breve, che è quello che F (e1_0) sembra fare –
Prismatic
@ 5gon12eder, quale compilatore stai usando? In VS2013 si compila senza 'esplicito'. So che la chiamata ambigua è per 'F', ma la causa è la conversione di' e1_0' in un tipo che un sovraccarico di 'F' accetta. Quando 'explicit' viene rimosso, il compilatore sceglie' B (E) 'per fare la conversione e chiama' F (B) '. Ho aggiunto 'esplicito' per essere sicuro, che non uso implicitamente il costruttore, che è un costruttore caso speciale nel mio codice reale. A mio parere, l'uso di 'explicit' dovrebbe guidare ancora di più il compilatore per utilizzare la conversione B (E) e non considerare una' enum E' per la promozione 'unsigned long'. – joja