2011-09-27 17 views
25

He estado buscando en todas partes esto, y no parece ser capaz de encontrar una respuesta directa. Algunas fuentes dicen que esto no es posible, pero eso solo genera más preguntas para mí, que explicaré más adelante.Pasando C++ Lambda Functions

Así que aquí está la situación. Supongamos que tengo una clase de contenedor personalizado con una función de selección, como a continuación (esto es sólo un ejemplo):

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

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

    // ... 
}; 

Así como se puede ver, la función select toma un puntero a una función condición. Esta es una función que define qué elementos se deben seleccionar. Por lo tanto, un ejemplo de uso de esto sería algo similar a:

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

Ahora bien, si tengo un recipiente lleno, digo s = { 1, 1, 0, 0, 1, 0, 1, 0 }, podría seleccionar un subconjunto de éstos que sólo contienen ceros usando:

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

Como puede ver, esto es un poco torpe. Las funciones lambda haría que este mucho más elegante, por lo que entonces podría usar (no estoy seguro si esto es la sintaxis correcta para ello), por ejemplo:

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

Mi pregunta es, ¿es esto posible? Si es así, ¿cuál debería ser el prototipo de mi función para Container::select() para aceptar una lambda como uno de sus parámetros?

Si no es posible, entonces ¿cómo se implementa algo como std::for_each que puede usar una expresión lambda como uno de sus argumentos? Cualquier recurso que explique claramente esto sería muy apreciado. Todo lo que he encontrado simplemente da ejemplos de funciones lambda y el uso de std::function<> para pasarlos como parámetros, pero nada explica cómo funciona std::for_each con funciones lambda.

Me gustaría señalar que este código no se compila/prueba como está. Solo para fines de demostración. Intenté implementar los mismos principios en el proyecto real y no funciona.

Respuesta

12

Debe declarar su lambda como sin estado (es decir, con una especificación de captura vacía [](int x)-> bool {...}) para que se pueda convertir a un puntero de función.

+6

O usar 'std :: function', o hacer' select 'una plantilla – bdonlan

+0

Intenté su solución (en el código exacto publicado anteriormente quitando' y '), y no funciona. Me da error C2664 porque no puede convertir '' anonymous-namespace ':: ' a 'bool (__cdecl *) (const T &)'. – Zeenobit

+1

@teedayf, es una adición más reciente a C++ 11. Visual Studio 2010 aún no lo admite. Y necesitaría declarar el lambda como '[] (const int & x) {...}' para que coincida con la firma del puntero a la función. – MSN

33

No es necesario agregar el reflejo [&] -capture. Su lambda no lo necesita:

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

lambdas Captureless son convertibles al puntero de función correspondiente, por lo que esto debería funcionar fuera de la caja.

Dicho esto, es probable que debe declarar la función de selección para aceptar std::function, a la que todos los lambdas son convertibles, capturando o no:

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