2016-01-26 14 views
7

Tôi muốn tạo lambda rằng sẽ chấp nhận bất kỳ số lượng các đối số như:Di chuyển tất cả các đối số cho lambda

template <typename... Args> 
void f(Args... args) { 
    auto l = [args...]() { 
     g(args...); 
    } 
    // use l 
} 

Vấn đề ở đây là nó không làm việc với thái chỉ loại. Nếu nó chỉ là 1 arg tôi sẽ làm smth như

void f(Arg arg) { 
    auto l = [arg = std::move(arg)]() { 
     g(move(arg)); 
    } 
} 

Làm thế nào để di chuyển tất cả args để lambda?

Trả lời

8
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); 
    }; 
} 

Một chút icky.

Đóng gói chúng thành một bộ, sau đó giải nén tuple bằng std::apply. Nếu bạn thiếu std::apply hãy viết cho mình một tài khoản tương đương.

Nếu bạn muốn gọi g với giá trị, hãy tắt lambda bên ngoài và move tuple vào lambda bên trong.

Bên trong lambda có thể chụp theo mặc định & nếu bạn muốn truy cập vào args của bên ngoài hoặc tương tự.

Chúng tôi thậm chí có thể trừu tượng mô hình này một chút:

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); 
    }; 
} 

sử dụng:

template <typename... Args> 
void f(Args... args) { 
    auto l = forward_capture(
    [](auto&&...args) { 
     g(args...); 
    }, 
    std::move(args)... 
); 
    // use l 
} 

Nếu bạn muốn danh sách chụp đầu tiên, chúng ta có thể làm điều đó:

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); 
    }; 
    }; 
} 

sử dụng :

template <typename... Args> 
void f(Args... args) { 
    auto l = forward_capture(std::move(args)...)(
    [](auto&&...args) { 
     g(args...); 
    } 
); 
    // use l 
} 

trong đó có "lợi thế" mà chúng tôi có 3 lambd lồng nhau.

Hoặc chi tiết thú vị:

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.

+0

Không đẹp, nhưng hoạt động :) – RiaD

+0

@RIAD trong khi tôi đang ở đó, đây là 2 biến thể. ;) – Yakk

+0

Tôi có câu hỏi về các lần chụp bằng trình khởi tạo. Tôi đọc rằng chúng chủ yếu dùng cho các kiểu di chuyển, nhưng không thể thay thế để làm '[x = std :: move (x)]' là lấy một tham chiếu rồi di chuyển -> '[&] {std: : di chuyển (x); } '? Di chuyển nó trong danh sách chụp có vẻ dư thừa với đôi mắt chưa được đào tạo của tôi. – 0x499602D2

Các vấn đề liên quan