Dada una lambda, ¿es posible descubrir su tipo de parámetro y el tipo de retorno? Si es así, ¿cómo?
Básicamente, quiero lambda_traits
que se pueda usar de las siguientes maneras:
auto lambda = [](int i) { return long(i*10); };
lambda_traits<decltype(lambda)>::param_type i; //i should be int
lambda_traits<decltype(lambda)>::return_type l; //l should be long
La motivación detrás es que quiero usar lambda_traits
una plantilla de función que acepte un lambda como argumento, y necesito saber su tipo de parámetro y el tipo de retorno dentro de la función:
template<typename TLambda>
void f(TLambda lambda)
{
typedef typename lambda_traits<TLambda>::param_type P;
typedef typename lambda_traits<TLambda>::return_type R;
std::function<R(P)> fun = lambda; //I want to do this!
//...
}
Por el momento, podemos suponer que la lambda toma exactamente un argumento.
Inicialmente, intenté trabajar std::function
como:
template<typename T>
A<T> f(std::function<bool(T)> fun)
{
return A<T>(fun);
}
f([](int){return true;}); //error
Pero obviamente daría error. Entonces lo cambié a la TLambda
versión de la plantilla de función y quiero construir el std::function
objeto dentro de la función (como se muestra arriba).
Respuestas:
Es curioso, acabo de escribir una
function_traits
implementación basada en Especializar una plantilla en una lambda en C ++ 0x que puede dar los tipos de parámetros. El truco, como se describe en la respuesta a esa pregunta, es usar el de la lambda .decltype
operator()
Tenga en cuenta que esta solución no funciona para lambda genérico como
[](auto x) {}
.fuente
tuple_element
embargo, no pensé en eso , gracias.const
, para aquellos lambda declaradosmutable
([]() mutable -> T { ... }
).operator()
no con esta implementación.auto
no es un tipo, por lo que nunca puede ser la respuesta atraits::template arg<0>::type
Aunque no estoy seguro de que esto sea estrictamente estándar, ideone compiló el siguiente código:
Sin embargo, esto proporciona solo el tipo de función, por lo que los tipos de resultados y parámetros deben extraerse de él. Si puede usar
boost::function_traits
,result_type
yarg1_type
cumplirá el propósito. Dado que ideone parece no proporcionar impulso en el modo C ++ 11, no pude publicar el código real, lo siento.fuente
El método de especialización que se muestra en la respuesta de @KennyTM se puede extender para cubrir todos los casos, incluidas las lambdas variables y mutables:
Demostración .
Tenga en cuenta que la aridad no está ajustada para
operator()
s variadic . En cambio, uno también puede consideraris_variadic
.fuente
La respuesta proporcionada por @KennyTMs funciona muy bien, sin embargo, si una lambda no tiene parámetros, el uso del índice arg <0> no se compila. Si alguien más tenía este problema, tengo una solución simple (más simple que usar soluciones relacionadas con SFINAE, es decir).
Simplemente agregue void al final de la tupla en la estructura arg después de los tipos de argumento variadic. es decir
Dado que la aridad no depende del número real de parámetros de plantilla, el real no será incorrecto, y si es 0, entonces al menos arg <0> seguirá existiendo y puede hacer lo que quiera. Si ya planea no superar el índice,
arg<arity-1>
entonces no debería interferir con su implementación actual.fuente