2011-01-19 15 views
10

Dato il seguente codice: -sovraccarico sui std :: funzione <...>

#include <algorithm> 
#include <iostream> 
#include <functional> 
#include <string> 

void func(std::function<void(void)> param) 
{ 
    param(); 
} 

void func(std::function<void(int)> param) 
{ 
    param(5); 
} 

int main(int argc, char* argv[]) 
{ 
    func([]() { std::cout << "void(void)" << std::endl; }); 
    func([] (int i) { std::cout << "void(int): " << i << std::endl; }); 

    std::string line; 
    std::getline(std::cin, line); 
    return 0; 
} 

errore di compilazione da VS2010: -

CppTest.cpp(18): error C2668: 'func' : ambiguous call to overloaded function 
1>   CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)' 
1>   with 
1>   [ 
1>    _Fty=void (int) 
1>   ] 
1>   CppTest.cpp(6): or  'void func(std::tr1::function<_Fty>)' 
1>   with 
1>   [ 
1>    _Fty=void (void) 
1>   ] 
1>   while trying to match the argument list '(`anonymous-namespace'::<lambda0>)' 
1>CppTest.cpp(19): error C2668: 'func' : ambiguous call to overloaded function 
1>   CppTest.cpp(11): could be 'void func(std::tr1::function<_Fty>)' 
1>   with 
1>   [ 
1>    _Fty=void (int) 
1>   ] 
1>   CppTest.cpp(6): or  'void func(std::tr1::function<_Fty>)' 
1>   with 
1>   [ 
1>    _Fty=void (void) 
1>   ] 
1>   while trying to match the argument list '(`anonymous-namespace'::<lambda1>)' 

errore di compilazione da g ++ - 4,5

program2.cpp: In function ‘int main(int, char**)’: 
program2.cpp:18:68: error: call of overloaded ‘func(main(int, char**)::<lambda()>)’ is ambiguous 
program2.cpp:6:10: note: candidates are: void func(std::function<void()>) 
program2.cpp:11:10: note:     void func(std::function<void(int)>) 
program2.cpp:19:79: error: call of overloaded ‘func(main(int, char**)::<lambda(int)>)’ is ambiguous 
program2.cpp:6:10: note: candidates are: void func(std::function<void()>) 
program2.cpp:11:10: note:     void func(std::function<void(int)>) 

Così sembra che il compilatore non riesca a capire che un lambda []() -> void può essere assegnato solo a una std :: function < void (void) > e un lambda [] (int) -> void può essere assegnato solo a una std :: function < void (int) >. Questo dovrebbe succedere o solo una carenza nei compilatori?

risposta

12

Si suppone che ciò accada o solo una carenza nei compilatori?

Questo dovrebbe succedere. std::function dispone di un modello di costruttore che può assumere un argomento di qualsiasi tipo. Il compilatore non può sapere fino a quando non viene selezionato un modello di costruttore e istanziato che si verificherà un errore, e deve essere in grado di selezionare un sovraccarico della funzione prima che possa farlo.

La correzione più semplice è quello di utilizzare un cast o di costruire in modo esplicito un oggetto del tipo corretto std::function:

func(std::function<void()>([](){})); 
func(std::function<void(int)>([](int){})); 

Se si dispone di un compilatore che supporta la conversione captureless-lambda-to-funzione di puntatore e il vostro lambda non cattura nulla, è possibile utilizzare i puntatori a funzione prime:

void func(void (*param)()) { } 
void func(void (*param)(int)) { } 

(sembra che si utilizza Visual C++ 2010, che non supporta questa conversione la conversione non è stato aggiunto alla specifica fino. solo befo re Visual Studio 2010 spedito, troppo tardi per aggiungerlo a)


di spiegare il problema in un po 'più in dettaglio, si consideri il seguente:.

template <typename T> 
struct function { 

    template <typename U> 
    function(U f) { } 
}; 

questo è fondamentalmente ciò che il std::function costruttore in la domanda ha il seguente aspetto: puoi chiamarla con qualsiasi argomento, anche se l'argomento non ha senso e causerebbe un errore da qualche altra parte. Ad esempio, function<int()> f(42); invocherebbe questo modello di costruttore con U = int.

Nel tuo esempio specifico, il compilatore trova due funzioni candidati durante la risoluzione di sovraccarico:

void func(std::function<void(void)>) 
void func(std::function<void(int)>) 

Il tipo di argomento, qualche indicibile lambda nome del tipo che si farà riferimento a come F, non corrisponde a uno di questi esattamente, quindi il compilatore inizia a guardare a quali conversioni può fare a F per cercare di farlo corrispondere a una di queste funzioni candidate. Durante la ricerca di conversioni, trova il modello di costruttore sopra menzionato.

Tutto il compilatore vede a questo punto è che si può chiamare entrambe le funzioni, perché

  • può convertire F per std::function<void(void)> utilizzando il suo costruttore di conversione con U = F e
  • può convertire F-std::function<void(int)> utilizzando la sua conversione costruttore con U = F.

Nel tuo esempio è ovvio che solo uno di questi avrà esito positivo senza errori, ma nel caso generale ciò non è vero. Il compilatore non può fare altro. Deve segnalare l'ambiguità e fallire. Non può sceglierne una perché entrambe le conversioni sono ugualmente buone e né il sovraccarico è migliore dell'altro.

+0

Dimmi se ho capito bene. Questo snippet ha lo stesso problema per lo stesso motivo (non è possibile istanziare Struct in tempo per determinare il sovraccarico della funzione)? 'modello struct Struct {Struct (T var) {}}; vuoto func2 (struct obj) {} vuoto func2 (struct obj) {} int main() {func2 (2.5); } ' – Arnavion

+0

No, è un po 'diverso da quello. Questo errore è dovuto al fatto che 'T' si trova in un contesto non condotto. Modificherò una spiegazione nella mia risposta; questo commento non è abbastanza grande. –

+0

Capito. Grazie! – Arnavion

Problemi correlati