9

Sto indagando su un C++ 11 linguaggio che potrebbe essere definito "lambda sovraccarico":C++ 11 "lambda sovraccarico" con il modello variadic e la cattura variabile

sovraccarico n funzioni con template variadic sembrava molto interessante per me, ma è venuto fuori che non ha funzionato con la cattura variabile: qualsiasi [&][=] 012.359.490,533 mila[&y] (e [this] etc se in una funzione membro) portano al fallimento di compilazione: error: no match for call to '(overload<main(int, char**)::<lambda(int)>, main(int, char**)::<lambda(char*)> >) (char*&)' (con il mio GCC 4.9.1 e locali ideone.com GCC 5.1)

D'altra parte, il caso 2-ario fisso didn' t soffrire di questo problema (Prova a cambiare il primo #if 0 a #if 1 su ideone.com)

Qualche idea su cosa sta succedendo qui? Si tratta di un bug del compilatore o sto differenziando dalle specifiche C++ 11/14?

http://ideone.com/dnPqBF

#include <iostream> 
using namespace std; 

#if 0 
template <class F1, class F2> 
struct overload : F1, F2 { 
    overload(F1 f1, F2 f2) : F1(f1), F2(f2) { } 

    using F1::operator(); 
    using F2::operator(); 
}; 

template <class F1, class F2> 
auto make_overload(F1 f1, F2 f2) { 
    return overload<F1, F2>(f1, f2); 
} 
#else 
template <class... Fs> 
struct overload; 

template <class F0, class... Frest> 
struct overload<F0, Frest...> : F0, overload<Frest...> { 
    overload(F0 f0, Frest... rest) : F0(f0), overload<Frest...>(rest...) {} 

    using F0::operator(); 
}; 

template <> 
struct overload<> { 
    overload() {} 
}; 

template <class... Fs> 
auto make_overload(Fs... fs) { 
    return overload<Fs...>(fs...); 
} 
#endif 

#if 0 
#define CAP 
#define PRINTY() 
#else 
#define CAP y 
#define PRINTY() cout << "int y==" << y << endl 
#endif 

int main(int argc, char *argv[]) { 
    int y = 123; 

    auto f = make_overload(
     [CAP] (int x) { cout << "int x==" << x << endl; PRINTY(); }, 
     [CAP] (char *cp) { cout << "char *cp==" << cp << endl; PRINTY(); }); 
    f(argc); 
    f(argv[0]); 
} 
+0

si dovrebbe avere ' utilizzando il sovraccarico :: operator(); 'nella seconda implementazione, [demo] (http://coliru.stacked-crooked.com/a/c908c85a29e04004) –

+0

e [questo è il motivo del sovraccarico con lavori lambda non catturanti] (http://coliru.stacked-crooked.com/a/dd9502d8e428c048) :-) –

+0

@Piot rSkotnicki Interessante, ma aggiungendo 'using overload :: operator();' non ha migliorato la situazione. – nodakai

risposta

8

risoluzione sovraccarico funziona solo per le funzioni che esistono in un ambito comune. Ciò significa che la seconda implementazione non riesce a trovare il secondo sovraccarico perché non importa gli operatori di chiamata di funzione da overload<Frest...> a overload<F0, Frest...>.

Tuttavia, un tipo lambda non acquisibile definisce un operatore di conversione su un puntatore di funzione con la stessa firma dell'operatore di chiamata della funzione lambda. Questo operatore di conversione può essere trovato per la ricerca del nome, e questo è ciò che viene richiamato quando si rimuove la parte che cattura.

La corretta applicazione, che funziona sia per la cattura e non cattura lambda, e che chiama sempre operator() al posto di un operatore di conversione, dovrebbe apparire come segue:

template <class... Fs> 
struct overload; 

template <class F0, class... Frest> 
struct overload<F0, Frest...> : F0, overload<Frest...> 
{ 
    overload(F0 f0, Frest... rest) : F0(f0), overload<Frest...>(rest...) {} 

    using F0::operator(); 
    using overload<Frest...>::operator(); 
}; 

template <class F0> 
struct overload<F0> : F0 
{ 
    overload(F0 f0) : F0(f0) {} 

    using F0::operator(); 
}; 

template <class... Fs> 
auto make_overload(Fs... fs) 
{ 
    return overload<Fs...>(fs...); 
} 

DEMO

+1

Si noti che se si desidera sovraccaricare molti (ad esempio più di 100) in un unico set di sovraccarico, è necessario modificare l'ereditarietà lineare con un'eredità binaria approssimativamente bilanciata. E vorrai rivedere il tuo design, perché stai sovraccaricando più di 100 lambda contemporaneamente? (Inoltre, la versione binaria è più codice) – Yakk