2011-09-27 29 views
25

Ho cercato dappertutto questo aspetto e non riesco a trovare una risposta diretta. Alcune fonti dicono che questo non è possibile, ma questo solleva più domande per me, che spiegherò più avanti.Passaggio alle funzioni lambda C++

Quindi, ecco la situazione. Supponiamo che io sono una classe contenitore personalizzato con una funzione di selezione come qui di seguito (questo è solo un esempio):

template <typename T> 
class Container { 
public: 
    // ... 

    Container<T> select(bool (*condition)(const T&)) const; 

    // ... 
}; 

Quindi, come si può vedere, la funzione select prende un puntatore ad una funzione condizioni. Questa è una funzione che definisce quali elementi devono essere selezionati. Così, un utilizzo esempio di questo potrebbe essere qualcosa di simile a:

bool zero_selector(const int& element) { 
    return (element == 0); // Selects all elements that are zero 
} 

Ora, se ho un contenitore riempito con, diciamo s = { 1, 1, 0, 0, 1, 0, 1, 0 }, ho potuto selezionare un sottoinsieme di questi che conterrebbe solo zeri utilizzando:

t = s.select(&zero_selector); // t = { 0, 0, 0, 0 } 

Come potete vedere, questo è un po 'goffo. funzioni lambda renderebbe questo molto più elegante, così poi ho potuto usare (non sono sicuro se questa è la sintassi corretta per esso), per esempio:

t = s.select([&] (int x) -> bool { return (x == 0); }); 

La mia domanda è, è possibile? In tal caso, quale dovrebbe essere il mio prototipo di funzione per Container::select() per accettare un lambda come uno dei suoi parametri?

Se non è possibile, come è implementato qualcosa come std::for_each che può utilizzare un'espressione lambda come uno dei suoi argomenti? Qualsiasi risorsa che spiegherebbe chiaramente questo sarebbe molto apprezzata. Tutto ciò che ho trovato fornisce solo esempi di funzioni lambda e l'utilizzo di std::function<> per passarli come parametri, ma nulla spiega come std::for_each funzioni con le funzioni lambda.

Mi piacerebbe notare che questo codice non è compilato/testato così com'è. È solo a scopo dimostrativo. Ho provato a implementare gli stessi principi nel progetto attuale e non funziona.

risposta

12

È necessario dichiarare il proprio lambda come stateless (ovvero con una specifica di acquisizione vuota [](int x)-> bool {...}) affinché sia ​​convertibile in un puntatore di funzione.

+6

Oppure utilizzare 'std :: function', o fare' selezionare 'un modello – bdonlan

+0

Ho provato la tua soluzione (sul codice esatto pubblicato sopra rimuovendo' '), e non funziona. Mi dà l'errore C2664 perché non può convertire ''namespace anonimo' :: 'in' bool (__cdecl *) (const T &) '. – Zeenobit

+1

@teedayf, è una nuova aggiunta a C++ 11. Visual Studio 2010 non lo supporta ancora. E dovresti dichiarare il lambda come '[] (const int & x) {...}' per abbinare la firma del puntatore alla funzione. – MSN

33

Non è necessario aggiungere l'innesco [&] -capture. Il tuo lambda non ne ha bisogno:

[] (int x) -> bool { return (x == 0); } 

Captureless lambda sono convertibili al puntatore a funzione corrispondente, quindi questo dovrebbe funzionare out of the box.

Detto questo, probabilmente si dovrebbe dichiarare la funzione di selezione di accettare std::function, al quale tutte le lambda sono convertibili, catturando o no:

Container<T> select(std::function<bool(const T&)> predicate) const; 
Problemi correlati