Le funzioni lambda possono essere modellate?

In C ++ 11, esiste un modo per creare una maschera con una funzione lambda? O è intrinsecamente troppo specifico per essere rappresentato da un modello?

Capisco che posso definire una classica class / functor basata su modelli, ma la domanda è più simile: il linguaggio consente le funzioni di lambda dei modelli?

AGGIORNAMENTO 2018: C ++ 20 arriverà con i lambda basati su modelli e concettualizzati. La funzione è già stata integrata nella bozza standard.


AGGIORNAMENTO 2014: C ++ 14 è stato rilasciato quest’anno e ora fornisce i lambda polimorfici con la stessa syntax che in questo esempio. Alcuni importanti compilatori lo implementano già.


Al suo stand (in C ++ 11), purtroppo no. I lambda polimorfici sarebbero eccellenti in termini di flessibilità e potenza.

La ragione originale per cui sono stati considerati monomorfici era a causa dei concetti. I concetti hanno reso difficile questa situazione del codice:

template  void foo(T x) { auto bar = [](auto x){}; // imaginary syntax } 

In un modello vincolato è ansible chiamare solo altri modelli vincolati. (Altrimenti non è stato ansible controllare i vincoli.) Può foo richiamare la bar(x) ? Quali vincoli ha il lambda (il parametro per questo è solo un modello, dopotutto)?

I concetti non erano pronti ad affrontare questo genere di cose; richiederebbe più cose come late_check (dove il concetto non è stato controllato fino a quando non è stato invocato) e roba del genere. Era più semplice abbandonare tutto e attenersi ai lambda monomorfi.

Tuttavia, con la rimozione dei concetti da C ++ 0x, i lambda polimorfi diventano di nuovo una proposizione semplice. Tuttavia, non riesco a trovare alcuna proposta per questo. 🙁

C ++ 11 lambda non può essere rappresentato come indicato in altre risposte, ma decltype() sembra essere d’aiuto quando si usa un lambda all’interno di una class o funzione decltype() modelli.

 #include  #include  using namespace std; template void boring_template_fn(T t){ auto identity = [](decltype(t) t){ return t;}; std::cout << identity(t) << std::endl; } int main(int argc, char *argv[]) { std::string s("My string"); boring_template_fn(s); boring_template_fn(1024); boring_template_fn(true); } 

stampe:

 My string 1024 1 

Ho trovato che questa tecnica è di aiuto quando si lavora con il codice basato su modelli, ma rendersi conto che significa che gli stessi lambda non possono essere rappresentati come modelli.

In C ++ 11, le funzioni lambda non possono essere basate su modelli, ma nella prossima versione dello standard ISO C ++ (spesso chiamato C ++ 14), verrà introdotta questa funzionalità. [Fonte]

Esempio di utilizzo:

 auto get_container_size = [] (auto container) { return container.size(); }; 

Si noti che sebbene la syntax utilizzi la parola chiave auto , la deduzione del tipo non utilizzerà le regole della deduzione del tipo auto , ma utilizzerà invece le regole della deduzione degli argomenti del modello. Vedi anche la proposta di espressioni lambda generiche (e l’ aggiornamento a questo).

Sono consapevole che questa domanda riguarda C ++ 11. Tuttavia, per coloro che sono stati cercati su Google in questa pagina, i lambdas basati su modelli sono ora supportati in C ++ 14 e vanno sotto il nome di Generic Lambdas.

[info] Molti dei popolari compilatori supportano questa funzione ora. Supporta Microsoft Visual Studio 2015. Supporti Clang. Supporti GCC.

Mi chiedo cosa ne pensi di questo:

 template  inline std::function templateLamda() { return [](){ std::cout << something.memberfunc() }; } 

Ho usato un codice simile come questo, per generare un template e mi chiedo se il compilatore ottimizzerà la funzione "wrapping".

Date un’occhiata a Boost.Phoenix per lambdas polimorfi: http://www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.html Non richiede C ++ 0x, dal modo 🙂

C’è un’estensione gcc che consente i modelli lambda :

 // create the widgets and set the label base::for_each(_widgets, []  (boost::fusion::pair& pair) -> void { pair.second = new Widget_T(); pair.second->set_label_str(Key_T::label); } ); 

dove _widgets è una std::tuple< fusion::pair... >

Non sono sicuro del motivo per cui nessun altro l’ha suggerito, ma puoi scrivere una funzione basata su modelli che restituisce funzioni lambda. Il seguente ha risolto il mio problema, la ragione per cui sono venuto a questa pagina:

 template  std::function makeUnweighted() { return [](DATUM datum){return 1.0;}; } 

Ora ogni volta che voglio una funzione che richiede un determinato tipo di argomento (ad es. std::string ), dico solo

 auto f = makeUnweighted() 

e ora f("any string") restituisce 1.0 .

Questo è un esempio di cosa intendo per “funzione lambda basata su modelli”. (Questo caso particolare viene utilizzato per fornire automaticamente una funzione di ponderazione inerte quando qualcuno non vuole pesare i propri dati, qualunque siano i loro dati.)

Ho giocato con l’ultima version 5.0.1 clang version 5.0.1 compilando il -std=c++17 e ora c’è un buon supporto per i parametri di tipo auto per lambdas:

 #include  #include  #include  int main() { auto slice = [](auto input, int beg, int end) { using T = decltype(input); const auto size = input.size(); if (beg > size || end > size || beg < 0 || end < 0) { throw std::out_of_range("beg/end must be between [0, input.size())"); } if (beg > end) { throw std::invalid_argument("beg must be less than end"); } return T(input.begin() + beg, input.begin() + end); }; auto v = std::vector { 1,2,3,4,5 }; for (auto e : slice(v, 1, 4)) { std::cout << e << " "; } std::cout << std::endl; } 

Ecco una soluzione che prevede il wrapping del lamba in una struttura:

 template  struct LamT { static void Go() { auto lam = []() { T var; std::cout << "lam, type = " << typeid(var).name() << std::endl; }; lam(); } }; 

Per usare fare:

 LamT::Go(); LamT::Go(); #This prints lam, type = i lam, type = c 

Il problema principale con questo (oltre alla tipizzazione extra) non è ansible incorporare questa definizione di struttura all'interno di un altro metodo o si ottiene (gcc 4.9)

 error: a template declaration cannot appear at block scope 

Ho anche provato a farlo:

 template  using LamdaT = decltype( [](void) { std::cout << "LambT type = " << typeid(T).name() << std::endl; }); 

Con la speranza che potrei usarlo in questo modo:

 LamdaT(); LamdaT(); 

Ma ottengo l'errore del compilatore:

 error: lambda-expression in unevaluated context 

Quindi questo non funziona ... ma anche se fosse compilato sarebbe di uso limitato perché dovremmo ancora mettere "l'uso di LamdaT" nell'ambito del file (perché è un modello) che sconfigge in qualche modo lo scopo di lambda.