Czy biorąc pod uwagę lambdę, można określić typ jej parametru i typ zwracany? Jeśli tak, w jaki sposób?
Zasadniczo chcę, aby lambda_traits
można było używać na następujące sposoby:
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
Motywacją jest to, że chcę użyć lambda_traits
w szablonie funkcji, który akceptuje lambdę jako argument, i muszę znać typ parametru i typ zwracany wewnątrz funkcji:
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!
//...
}
Na razie możemy założyć, że lambda przyjmuje dokładnie jeden argument.
Początkowo starałem się współpracować z std::function
:
template<typename T>
A<T> f(std::function<bool(T)> fun)
{
return A<T>(fun);
}
f([](int){return true;}); //error
Ale to oczywiście powodowałoby błąd. Więc zmieniłem go na TLambda
wersję szablonu funkcji i chcę skonstruować std::function
obiekt wewnątrz funkcji (jak pokazano powyżej).
Odpowiedzi:
Zabawne, właśnie napisałem
function_traits
implementację opartą na specjalizacji szablonu na lambdzie w C ++ 0x, która może podać typy parametrów. Sztuczka, jak opisano w odpowiedzi na to pytanie, polega na użyciu lambda .decltype
operator()
Zauważ, że to rozwiązanie nie działa dla generycznych, takich jak lambda
[](auto x) {}
.źródło
tuple_element
, dzięki.const
, dla tych deklarowanych lambdamutable
([]() mutable -> T { ... }
).operator()
nie z tą implementacją.auto
nie jest typem, więc nigdy nie może być odpowiedzią natraits::template arg<0>::type
Chociaż nie jestem pewien, czy jest to ściśle zgodne ze standardami, ideone skompilowało następujący kod:
Jednak zapewnia to tylko typ funkcji, więc wyniki i typy parametrów muszą zostać wyodrębnione z niego. Jeśli można użyć
boost::function_traits
,result_type
aarg1_type
spotka się z celem. Ponieważ ideone wydaje się nie zapewniać przyspieszenia w trybie C ++ 11, nie mogłem opublikować rzeczywistego kodu, przepraszam.źródło
Metodę specjalizacji pokazaną w odpowiedzi @KennyTM można rozszerzyć tak, aby obejmowała wszystkie przypadki, w tym zmienne i zmienne lambdy:
Demo .
Należy zauważyć, że arancja nie jest dostosowana do wariadycznych
operator()
. Zamiast tego można również rozważyćis_variadic
.źródło
Odpowiedź udzielona przez @KennyTMs działa świetnie, jednak jeśli lambda nie ma parametrów, użycie indeksu arg <0> nie jest kompilowane. Jeśli ktoś inny miał ten problem, mam proste rozwiązanie (to znaczy prostsze niż używanie rozwiązań powiązanych z SFINAE).
Po prostu dodaj void na końcu krotki w strukturze arg po różnych typach argumentów. to znaczy
ponieważ liczba nie zależy od faktycznej liczby parametrów szablonu, rzeczywista nie będzie niepoprawna, a jeśli wynosi 0, to przynajmniej arg <0> będzie nadal istniał i możesz z nim zrobić, co chcesz. Jeśli planujesz już nie przekraczać indeksu,
arg<arity-1>
nie powinno to kolidować z bieżącą implementacją.źródło