C ++ 11 “lambda sovraccaricata” con modello variadico e cattura variabile

Sto studiando un linguaggio C ++ 11 che potrebbe essere chiamato “lambda sovraccarico”:

  • http://cpptruths.blogspot.com/2014/05/fun-with-lambdas-c14-style-part-2.html
  • http://martinecker.com/martincodes/lambda-expression-overloading/

Il sovraccarico di n funzioni con il modello variadico mi è sembrato molto allettante ma si è scoperto che non funzionava con l’acquisizione di variabili: nessuna di [&] [=] [y] [&y] (e [this] ecc se in una funzione membro) portare alla compilazione fallita: error: no match for call to '(overload<main(int, char**)::, main(int, char**):: >) (char*&)' (con il mio GCC locale 4.9.1 e ideone.com GCC 5.1)

D’altra parte, il caso fisso 2-ary non ha sofferto 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  using namespace std; #if 0 template  struct overload : F1, F2 { overload(F1 f1, F2 f2) : F1(f1), F2(f2) { } using F1::operator(); using F2::operator(); }; template  auto make_overload(F1 f1, F2 f2) { return overload(f1, f2); } #else template  struct overload; template  struct overload : F0, overload { overload(F0 f0, Frest... rest) : F0(f0), overload(rest...) {} using F0::operator(); }; template  struct overload { overload() {} }; template  auto make_overload(Fs... fs) { return overload(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]); } 

La risoluzione del 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 si importano gli operatori di chiamata di funzione da overload in overload .

Tuttavia, un tipo lambda non catturante definisce un operatore di conversione su un puntatore di funzione con la stessa firma dell’operatore di chiamata di 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.

L’implementazione corretta, che funziona sia per lambdas di cattura che di non cattura, e che chiama sempre operator() invece di un operatore di conversione, dovrebbe avere il seguente aspetto:

 template  struct overload; template  struct overload : F0, overload { overload(F0 f0, Frest... rest) : F0(f0), overload(rest...) {} using F0::operator(); using overload::operator(); }; template  struct overload : F0 { overload(F0 f0) : F0(f0) {} using F0::operator(); }; template  auto make_overload(Fs... fs) { return overload(fs...); } 

DEMO