2016-06-22 44 views
5

Ho scritto un codice che recupera i tipi dei parametri non automatici quando viene fornita una funzione lambda generica. Come puoi vedere nel codice qui sotto, l'idea è di chiamare la funzione connect con un lambda generico e fornire argomenti per i parametri auto (che saranno sempre in primo piano nel mio caso d'uso). Quindi nel codice qui sotto il mio obiettivo era rilevare che il secondo parametro è di tipo float.Rilevamento dei tipi di parametri da lambda - errore di compilazione generico con GCC

Il codice funziona bene con clang 3.8 ma non è compilato con gcc 6.1.1, quindi mi chiedevo se si trattava di un bug in gcc o se questo non è valido codice C++? Posso supporre che un lambda generico sia implementato con una funzione operatorata() o questo compilatore sia specifico?

template <typename Functor, typename... AllArgs, typename... ProvidedArgs> 
void findArgTypes(void(Functor::*)(AllArgs...) const, Functor, ProvidedArgs...) 
{ 
    // AllArgs == int, float 
    // ProvidedArgs == int 
} 

template <typename Func, typename... ProvidedArgs> 
void connect(Func func, ProvidedArgs... providedArgs) 
{ 
    findArgTypes(&Func::template operator()<ProvidedArgs...>, func, providedArgs...); 
} 

int main() 
{ 
    int tmp = 0; 
    connect([&](auto, float){ ++tmp; }, 0); 
} 

L'errore che gcc dà è questo:

main.cpp: In instantiation of ‘void connect(Func, ProvidedArgs ...) [with Func = main()::<lambda(auto:1, float)>; ProvidedArgs = {int}]’: 
main.cpp:16:33: required from here 
main.cpp:11:17: error: no matches converting function ‘operator()’ to type ‘void (struct main()::<lambda(auto:1, float)>::*)() const’ 
    findArgTypes(&Func::template operator()<ProvidedArgs...>, func, providedArgs...); 
    ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:16:27: note: candidate is: template<class auto:1> main()::<lambda(auto:1, float)> 
    connect([](auto, float){}, 0); 
         ^

Rimozione del const nel findArgTypes dà lo stesso risultato.

utilizzando il seguente codice funziona con entrambi i compilatori:

struct Foo 
{ 
    template <typename T> 
    void operator()(T, float) const {} 
}; 

int main() 
{ 
    Foo f; 
    connect(f, 0); 
} 

risposta

1

Hai errore perché vi aspettate funtore (oggetto), ma lambda con la cattura vuoto è convertibile in funzione libera:

int main() { 
    using function = void (*)(int, float); 
    function a = [](auto, float){}; 
} 

See lambda from cppreference:


Per la più recente versione della sua domanda che soddisfi entrambi i compilatori di implementazione:

template <typename Func, typename... ProvidedArgs> 
void connect(Func func, ProvidedArgs... providedArgs) 
{ 
    auto mf = &Func::template operator()<ProvidedArgs...>; 
    findArgTypes(mf, func, providedArgs...); 
} 

Penso che questo sia gcc bug del compilatore che le esigenze di gcc questa variabile locale auto per funzionare correttamente ...

proposito, una domanda - un bug in clang, uno in gcc - Ti consiglio davvero di trovare un modo più semplice per raggiungere i tuoi obiettivi - forse prendere in considerazione l'uso di std::function invece di un generico lambda?

+0

Questo codice sembra compilare con gcc ma non con clang. Ma cambiare il mio codice per prendere 'void (*) (AllArgs ...)' come primo parametro di findArgTypes dà ancora lo stesso errore con gcc (e non funziona più con clang). Anche la cattura di una variabile locale non sembra fare la differenza. – texus

+0

Hai bisogno di due funzioni sovraccariche - una per le funzioni libere, una per le funzioni oggetto - o semplicemente cambia un po 'il tuo design ... – PiotrNycz

+0

clang potrebbe essere sbagliato - vedi esempio dalla pagina collegata: 'int & (* fpi) (int *) = [] (auto * a) -> auto & {return * a; }; // ok' – PiotrNycz

Problemi correlati