Dado um lambda, é possível descobrir seu tipo de parâmetro e tipo de retorno? Se sim, como?
Basicamente, eu quero o lambda_traits
que pode ser usado das seguintes maneiras:
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
A motivação por trás disso é que eu quero usar lambda_traits
em um modelo de função que aceita um lambda como argumento, e preciso saber o tipo de parâmetro e o tipo de retorno dentro da função:
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 enquanto, podemos assumir que o lambda leva exatamente um argumento.
Inicialmente, tentei trabalhar std::function
como:
template<typename T>
A<T> f(std::function<bool(T)> fun)
{
return A<T>(fun);
}
f([](int){return true;}); //error
Mas, obviamente, daria erro. Então eu mudei para a TLambda
versão do modelo de função e quero construir o std::function
objeto dentro da função (como mostrado acima).
Respostas:
Engraçado, acabei de escrever uma
function_traits
implementação baseada em Especializando um modelo em um lambda em C ++ 0x, que pode fornecer os tipos de parâmetros. O truque, conforme descrito na resposta dessa pergunta, é usar o dos lambda .decltype
operator()
Observe que esta solução não funciona para lambda genérico como
[](auto x) {}
.fonte
tuple_element
nisso, obrigado.const
, para aqueles lambda declaradosmutable
([]() mutable -> T { ... }
).operator()
não nessa implementação.auto
não é um tipo, por isso nunca pode ser a resposta paratraits::template arg<0>::type
Embora eu não tenha certeza de que isso seja estritamente padrão, o ideone compilou o seguinte código:
No entanto, isso fornece apenas o tipo de função, portanto, os tipos de resultado e parâmetro precisam ser extraídos dela. Se você pode usar
boost::function_traits
,result_type
earg1_type
cumprirá o objetivo. Como o ideone parece não fornecer impulso no modo C ++ 11, não pude postar o código real, desculpe.fonte
O método de especialização mostrado na resposta do @KennyTM pode ser estendido para cobrir todos os casos, incluindo lambdas variadas e mutáveis:
Demo .
Observe que a aridade não é ajustada para
operator()
s variáveis . Em vez disso, também se pode consideraris_variadic
.fonte
A resposta fornecida pelo @KennyTMs funciona muito bem, no entanto, se um lambda não tiver parâmetros, o uso do índice arg <0> não será compilado. Se alguém mais estava tendo esse problema, eu tenho uma solução simples (mais simples do que usar soluções relacionadas à SFINAE).
Apenas adicione void ao final da tupla na estrutura arg após os tipos de argumentos variados. ie
como a arity não depende do número real de parâmetros do modelo, o real não estará incorreto e, se for 0, pelo menos arg <0> ainda existirá e você poderá fazer o que quiser. Se você já planeja não exceder o índice
arg<arity-1>
, ele não deve interferir na sua implementação atual.fonte