c++
Pase la expresión lambda al argumento lambda c++ 11 (5)
Es posible que tenga que simplemente morder la bala e implementar sus propios funtores como lo hicimos en la Edad Media:
struct F {
int x;
int y;
F(int x_, int y_) : x(x_), y(y_) {}
template <typename G>
double operator() (G&& g) const {
g(0);
return 0.0;
}
};
#include <iostream>
int main()
{
int x = 0;
int y = 0;
auto f = F(x, y);
f([x](int i){return 0.0;});
f([](int i){std::cout << i << std::endl;});
}
Eso debería hacer que continúes hasta que tu compilador soporte lambdas genéricas de C ++ 14.
Me gustaría hacer algo como esto:
int main()
{
auto f = [/*some variables*/](/*take lambda function*/)
{/*something with lambda function*/};
f([/*other variables*/](/*variables to be decided by f()*/)
{/*something with variables*/});
}
Sé que es posible pasar un lambda a una función, así como a un lambda. Los siguientes trabajos:
int main()
{
int x=0;
int y=0;
auto f = [x,y](double (func)(int)) -> double
{func(0); return 0.0;};
f([](int i) -> double
{return 0.0;});
}
Pero lo siguiente no funciona (tan pronto como cambio las variables de alcance para agregar [x])
int main()
{
int x=0;
int y=0;
auto f = [x,y](double (func)(int)) -> double
{func(0); return 0.0;}
f([x](int i) -> double //[x] does not work
{return 0.0;});
}
lo que da el error:
error: function "lambda [](double (*)(int))->double::operator()" cannot be called with the given argument list
argument types are: (lambda [](int)->double)
object type is: lambda [](double (*)(int))->double
¿Alguien tendría una idea de cómo solucionar esto, o una forma de evitarlo? Estoy usando el compilador icpc de Intel (ICC) 13.1.2 con std = c ++ 11
Gracias
Hay un par de cosas que aclarar con respecto a su pregunta. ¿El primero de los cuales es lo que es un lambda?
Una expresión lambda es una expresión simple desde la cual el compilador generará un tipo único que no puede ser nombrado, y al mismo tiempo generará una instancia del tipo. Cuando escribe: [](int i) { std::cout << i; }
[](int i) { std::cout << i; }
el compilador generará un tipo para usted que es aproximadamente:
struct __lambda_unique_name {
void operator()(int i) const { std::cout << i; }
};
Como puede ver, no es una función, sino un tipo que implementa operator()
como una función miembro const
. Si la lambda realiza alguna captura, el compilador generará un código para capturar el valor / las referencias.
Como un caso de esquina, para las lambdas como la anterior, donde no se captura ningún estado, el idioma permite una conversión del tipo lambda a un puntero para que funcione con la firma del operator()
(menos la parte correspondiente), por lo que el lambda anterior se puede convertir implícitamente en un puntero para que funcione tomando int
y no devuelva nada:
void (*f)(int) = [](int i) { std::cout << i; }
Ahora que se han establecido los conceptos básicos, en su código tiene esta lambda:
auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;};
Las reglas para los parámetros a las funciones (que también se aplican a las lambdas) determinan que un argumento no puede ser de tipo función , por lo que el argumento a la lambda decae a un puntero a la función (de la misma manera que un argumento de tipo array decae a un puntero tipo):
auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;};
En un momento posterior, está intentando pasar un lambda que tiene una captura como argumento. Debido a que hay una captura, la regla especial no se aplica y la lambda no se puede convertir en un puntero a la función que produce el error del compilador que ve.
En la norma actual puede ir de una de dos maneras. Puede usar el borrado de tipo para eliminar el tipo exacto de la entidad exigible de la firma:
auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;};
Debido a que std::function<double(int)>
se puede inicializar con cualquier entidad invocable con la firma apropiada, esto aceptará las lambdas en el código a continuación, al costo del borrado de tipo que generalmente implica una asignación dinámica y un envío dinámico .
Alternativamente, puede soltar el azúcar sintáctico y hacer rodar el primer equivalente lambda manualmente, pero hacerlo genérico. En este caso, donde la lambda es simple, esta podría ser una opción válida:
struct mylambda {
template <typename F>
double operator()(F fn) const {
fn(0); return 0.0;
}
} f;
// then use the non-lambda as you tried:
f([x](int i) -> double {return 0.0;});
Finalmente, si es lo suficientemente paciente, puede esperar a C ++ 14, donde (lo más probable es que aún no haya sido ratificado) habrá soporte para las lambdas polimórficas que simplifican la creación de la clase anterior:
auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to ''mylambda'' above
Intenta usar la función std ::
#include <functional>
int main()
{
int x=0;
int y=0;
auto f = [x,y](std::function<double(int)> func) -> double
{func(0); return 0.0;};
f([x](int i) -> double {return 0.0;});
}
Puede especificar un lambda de captura, pero esta solución tiene sus limitaciones:
#include <new>
#include <utility>
namespace
{
template <typename F, int I, typename L, typename R, typename ...A>
inline F cify(L&& l, R (*)(A...) noexcept(noexcept(
std::declval<F>()(std::declval<A>()...))))
{
static L l_(std::forward<L>(l));
static bool full;
if (full)
{
l_.~L();
new (static_cast<void*>(&l_)) L(std::forward<L>(l));
}
else
{
full = true;
}
return [](A... args) noexcept(noexcept(
std::declval<F>()(std::forward<A>(args)...))) -> R
{
return l_(std::forward<A>(args)...);
};
}
}
template <typename F, int I = 0, typename L>
inline F cify(L&& l)
{
return cify<F, I>(std::forward<L>(l), F());
}
int main()
{
int x=0;
int y=0;
auto f = [x,y](double (func)(int)) -> double
{func(0); return 0.0;};
f(cify<double(*)(int i)>([x](int i) -> double //works now
{return 0.0;}));
}
Click para ver un ejemplo de trabajo.
Puede probar algo como lo siguiente si conoce el tipo de lambda de antemano, por ejemplo:
int main()
{
int x = 0, y = 0;
auto f = [x]( int i )->double {
return (double)x;
};
auto f2 = [x,y]( decltype(f) func )->double {
return func( 0 );
};
f2( f );
return 0;
}
O como alternativa, podría usar la biblioteca <functional>
para una solución más genérica, por ejemplo:
auto f = [x,y]( std::function<double(int)> func ) { /* Do stuff */ };