funciones examples c++ c++11 lambda

funciones - lambda examples c++



Lambda funciona como clases base (2)

Además de operator() , una clase definida por una lambda puede (en las circunstancias adecuadas) proporcionar una conversión a un puntero para funcionar. La circunstancia (o al menos la principal) es que la lambda no puede capturar nada.

Si agrega una captura:

auto f1 = get( []() { std::cout << "lambda1::operator()()/n"; }, [i](int) { std::cout << "lambda2::operator()(int)/n"; } ); f1(); f1(2);

... ya no se proporciona la conversión de pointer to function , por lo que tratar de compilar el código anterior genera el error que probablemente esperaba desde el principio:

trash9.cpp: In function ''int main(int, char**)'': trash9.cpp:49:9: error: no match for call to ''(Overload<main(int, char**)::<lambda()>, main(int, char**)::<lambda(int)> >) (int)'' trash9.cpp:14:8: note: candidate is: trash9.cpp:45:23: note: main(int, char**)::<lambda()> trash9.cpp:45:23: note: candidate expects 0 arguments, 1 provided

Jugando con Lambdas encontré un comportamiento interesante que no entiendo del todo.

Supongo que tengo una struct Overload que se deriva de 2 parámetros de plantilla, y tiene un using F1::operator(); cláusula.

Ahora bien, si provengo de dos funtores, solo puedo acceder al operador () de F1 (como era de esperar)

Si derivo de dos funciones Lambda esto ya no es cierto: también puedo acceder al operador () desde F2.

#include <iostream> // I compiled with g++ (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8) // // g++ -Wall -std=c++11 -g main.cc // g++ -Wall -std=c++11 -DFUNCTOR -g main.cc // // or clang clang version 3.3 (tags/RELEASE_33/rc2) // // clang++ -Wall -std=c++11 -g main.cc // clang++ -Wall -std=c++11 -DFUNCTOR -g main.cc // // on a Linux localhost.localdomain 3.9.6-200.fc18.i686 #1 SMP Thu Jun 13 // 19:29:40 UTC 2013 i686 i686 i386 GNU/Linux box struct Functor1 { void operator()() { std::cout << "Functor1::operator()()/n"; } }; struct Functor2 { void operator()(int) { std::cout << "Functor2::operator()(int)/n"; } }; template <typename F1, typename F2> struct Overload : public F1, public F2 { Overload() : F1() , F2() {} Overload(F1 x1, F2 x2) : F1(x1) , F2(x2) {} using F1::operator(); }; template <typename F1, typename F2> auto get(F1 x1, F2 x2) -> Overload<F1, F2> { return Overload<F1, F2>(x1, x2); } int main(int argc, char *argv[]) { auto f = get(Functor1(), Functor2()); f(); #ifdef FUNCTOR f(2); // this one doesn''t work IMHO correctly #endif auto f1 = get( []() { std::cout << "lambda1::operator()()/n"; }, [](int) { std::cout << "lambda2::operator()(int)/n"; } ); f1(); f1(2); // this one works but I don''t know why return 0; }

La norma establece que:

El tipo de expresión lambda (que también es el tipo de objeto de cierre) es un tipo de clase no sindical sin nombre único

Entonces cada tipo de Lambda debe ser único.

No puedo explicar por qué esto es así: ¿alguien puede arrojar algo de luz sobre esto, por favor?


Una lambda genera una clase de functor.

¡De hecho, puedes derivar de lambdas y tener lambdas polimórficos!

#include <string> #include <iostream> int main() { auto overload = make_overload( [](int i) { return ''['' + std::to_string(i) + '']''; }, [](std::string s) { return ''['' + s + '']''; }, [] { return "[void]"; } ); std::cout << overload(42) << "/n"; std::cout << overload("yay for c++11") << "/n"; std::cout << overload() << "/n"; }

Huellas dactilares

[42] [yay for c++11] [void]

¿Cómo?

template <typename... Fs> Overload<Fs...> make_overload(Fs&&... fs) { return { std::forward<Fs>(fs)... }; }

Por supuesto ... esto aún oculta la magia. Es la clase de Overload que ''mágicamente'' deriva de todas las lambdas y expone el operator() correspondiente operator() :

#include <functional> template <typename... Fs> struct Overload; template <typename F> struct Overload<F> { Overload(F&& f) : _f(std::forward<F>(f)) { } template <typename... Args> auto operator()(Args&&... args) const -> decltype(std::declval<F>()(std::forward<Args>(args)...)) { return _f(std::forward<Args>(args)...); } private: F _f; }; template <typename F, typename... Fs> struct Overload<F, Fs...> : Overload<F>, Overload<Fs...> { using Overload<F>::operator(); using Overload<Fs...>::operator(); Overload(F&& f, Fs&&... fs) : Overload<F>(std::forward<F>(f)), Overload<Fs...>(std::forward<Fs>(fs)...) { } }; template <typename... Fs> Overload<Fs...> make_overload(Fs&&... fs) { return { std::forward<Fs>(fs)... }; }

Véalo en vivo en Coliru