2015-12-26 20 views
5

Ho scritto questo codice per verificare se un tipo di classe ha la funzione begin.Perché la risoluzione del sovraccarico è ambigua in questo caso?

struct foo //a simple type to check 
{ 
    int begin(){ return 0;} 
}; 

struct Fallback 
{ 
    int begin(){ return 0;} 
}; 

template<typename T> 
struct HasfuncBegin : T,Fallback 
{ 
    typedef char one; 
    typedef int two; 

    template<typename X> 
    static one check(int (X::*)() = &HasfuncBegin<T>::begin); 
    template<typename X> 
    static two check(...); 

    enum :bool {yes = sizeof(check<T>())==1, no= !yes}; 
}; 

int main() 
{ 
    std::cout<< HasfuncBegin<foo>::yes; 
    return 0; 
} 

che produce errore:

error: call of overloaded 'check()' is ambiguous 
    enum {yes = sizeof(check<T>())==1, no= !yes}; 
           ^
C:\XXX\main.cpp:24:16: note: candidate: static HasfuncBegin<T>::one HasfuncBegin<T>::check(int (X::*)()) [with X = foo; T = foo; HasfuncBegin<T>::one = char] 
    static one check(int (X::*)() = &HasfuncBegin<T>::begin); 
       ^
C:\XXX\main.cpp:26:16: note: candidate: static HasfuncBegin<T>::two HasfuncBegin<T>::check(...) [with X = foo; T = foo; HasfuncBegin<T>::two = int] 
    static two check(...); 


     ^

Qualcuno può spiegare perché chiamata è ambigua (anche se prima funzione di controllo con la firma one check(int (X::*)() = &HasfuncBegin<T>::begin); ha argomento di default da utilizzare) e anche il modo di fare il mio codice lavoro?

Edit:

Così qui è il codice finale di lavoro:

struct foo 
{ 
    int begin(){ return 0;} 
}; 

struct Fallback 
{ 
    int begin(){ return 0;} 
}; 

template<typename T, T ptr> struct dummy{}; 

template<typename T> 
struct HasfuncBegin : T,Fallback 
{ 
    typedef char one; 
    typedef int two; 


    template<typename X> 
    static one check(dummy<int (X::*)(),&HasfuncBegin<X>::begin>*); 
// even this won't work, so replace above statement with below commented one 
// static one check(dummy<decltype(&HasfuncBegin<X>::begin),&HasfuncBegin<X>::begin>*); 
    template<typename X> 
    static two check(...); 

    enum {yes = sizeof(check<T>(0))==1, no= !yes}; 
}; 
+0

Perché non usare qualcosa come 'typename std :: condizionale :: value, uno, due> :: type'? –

+0

Gli argomenti della funzione predefinita non fanno parte della firma della funzione e non vengono considerati da SFINAE. – cpplearner

+0

Possibile duplicato di http://stackoverflow.com/q/257288/1639256 o http://stackoverflow.com/q/1966362/1639256 – Oktalist

risposta

0

La chiamata è ambigua perché la selezione del sovraccarico si basa sulle sequenze di conversione dagli argomenti di chiamata ai parametri di funzione. Le regole sono un po 'complessa da spiegare completamente qui, ma considerano questi due esempi:

void ex1(int) {} //v1 
void ex1(...) {} //v2 

void ex2(int = 1) {} //v1 
void ex2(...) {} //v2 

int main() { 
    ex1(1); 
    ex2(); 
} 

La chiamata ex1(1) è ben formato. Esiste un singolo argomento che ha una sequenza di conversione implicita migliore a v1 rispetto a v2 (conversione corrispondenza esatta con ellissi).

La chiamata ex2() non è corretta. Non ci sono argomenti con cui confrontare le sequenze di conversione ed entrambi i sovraccarichi possono essere chiamati senza argomenti. Questo è analogo al tuo codice.


Sembra che sei bloccato con C++ 03, quindi ecco una possibile soluzione usando this answer:

template<typename T>        
struct HasfuncBegin {              
    typedef char yes[1];            
    typedef char no [2];            
    template <typename U, U> struct type_check;      
    template <typename _1> static yes &chk(type_check<int (T::*)(), &_1::begin > *); 
    template <typename > static no &chk(...);      
    static bool const value = sizeof(chk<T>(0)) == sizeof(yes);  
}; 

Live Demo

+0

Puoi correggere il mio codice usando il meccanismo di fallback che stavo cercando di usare? Grazie) –

+0

Non capisco appieno a cosa serve il fallback. Stai pensando di ereditare da 'HasfuncBegin' in modo da ottenere il valore predefinito se la classe specificata non ne ha uno? – TartanLlama

+0

BTW il commento nella domanda originale: "Inoltre non stai facendo SFINAE perché non viene dedotto alcun argomento modello" ha senso per te signore? Grazie –

3

La ragione per l'ambiguità è che entrambi (su modelli) sovraccarichi di check() sono partite valide per check<T>(). Si può pensare che uno sia più valido dell'altro, ma le regole della lingua sono che sono entrambi ugualmente validi.

Una funzione argomento variabile (...) corrisponde a zero o più argomenti (ad esempio check<T>()). Una funzione con un singolo argomento che ha un valore predefinito può corrispondere a check<T>().

Da qui il messaggio sull'ambiguità.

Non hai effettivamente descritto cosa stai cercando di ottenere con questo codice (in particolare l'inizializzazione di enum), ma in qualche modo ti aspetti che risolviamo ciò che stai cercando di fare. Il modo ovvio per farlo compilare sarebbe rimuovere uno dei sovraccarichi.

Ma, a meno che tu non descriva quello che stai davvero cercando di ottenere, nessuno può consigliarti. Leggere siti come questo non garantisce ai giocatori poteri di mindreading.

+0

Cosa ho ' Il tentativo di raggiungere è scritto nella prima riga della domanda: 'Ho scritto questo codice per verificare se un tipo di classe ha iniziato la funzione. –

+0

E quella descrizione è insufficiente. Scusate. – Peter

+0

@Peter Non è chiaro dal codice? Se esiste una funzione membro 'begin()', si suppone che 'yes' nell'enum sia vero. A seconda della risoluzione del sovraccarico viene scelto uno o l'altro 'check()', che porta a un valore diverso per 'yes' (non funziona, ma era l'idea). –

Problemi correlati