template <class... Args>
void f(Args... args) {
auto l = [tup=std::make_tuple(std::move(args)...)] {
std::apply([](auto&&...args){
g(decltype(args)(args)...);
}, tup);
};
}
Trochę icky.
Zapakuj je do krotki, a następnie rozpakuj krotkę przy pomocy std::apply
. Jeśli brakuje Ci std::apply
napisz sobie odpowiednik.
Jeśli chcesz wywołać g
z wartościami r, ustaw zewnętrzną zmienną lambda i move
tuple w wewnętrzną lambdę.
Wewnętrzna lambda może przechwycić domyślnie &
, jeśli chcesz uzyskać dostęp do argumentów zewnętrznych lub podobnych.
Możemy nawet abstrakcyjny wzór ten nieco:
template<class F, class...Args>
auto forward_capture(F&& f, Args&&...args) {
return [
f=std::forward<F>(f),
tup=std::make_tuple(std::forward<Args>(args)...)
]{
return std::apply(f, tup);
};
}
zastosowanie:
template <typename... Args>
void f(Args... args) {
auto l = forward_capture(
[](auto&&...args) {
g(args...);
},
std::move(args)...
);
// use l
}
Jeśli chcesz najpierw listę przechwytywania, możemy to zrobić:
template<class...Args>
auto forward_capture(Args&&...args) {
return [
tup=std::make_tuple(std::forward<Args>(args)...)
](auto&& f)mutable{
return [
f=decltype(f)(f),
tup=std::move(tup)
]{
return std::apply(f, tup);
};
};
}
korzystania :
template <typename... Args>
void f(Args... args) {
auto l = forward_capture(std::move(args)...)(
[](auto&&...args) {
g(args...);
}
);
// use l
}
który ma "zaletę", że mamy 3 zagnieżdżone lambdy.
Albo więcej zabawy:
template<class...Args>
struct arrow_star {
std::tuple<Args...> args;
template<class F>
auto operator->*(F&& f)&& {
return [f=std::forward<F>(f),args=std::move(args)]()mutable{
return std::experimental::apply(std::move(f), std::move(args));
};
}
};
template<class...Args>
arrow_star<std::decay_t<Args>...> forward_capture(Args&&...args) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
template<class...Args>
auto f(Args... args)
{
return
forward_capture(std::move(args)...)
->*
[](auto&&...args){
g(decltype(args)(args)...);
};
}
live example.
Nie tak piękne, ale działa :) – RiaD
@RiaD gdy jestem na tym, oto 2 warianty. ;) – Yakk
Mam pytanie dotyczące przechwytywania za pomocą inicjalizatorów. Czytałem, że są one głównie dla typów typu "ruch", ale nie może być alternatywą dla zrobienia '[x = std :: move (x)], aby wziąć referencję, a następnie przenieść ->' [&] {std: : move (x); } '? Przeniesienie go na listę przechwytywania wydaje się zbędne dla moich niewprawnych oczu. – 0x499602D2