2013-03-21 33 views
14

Tại thời điểm tôi đang gặp khó khăn cố gắng để lưu trữ một gói thông số, đây là đoạn mã nguồn của thiết kế:C++ Làm thế nào để lưu trữ một gói thông số như là một biến

template<typename Func, typename... Args> 
void handleFunc(Func func, Args&&... args) { 
    struct nest { 
     Func nestFunc; 
     Args... nestArgs; // I DONT KNOW WHAT TO DO HERE 
     void setup(Func func, Args... args) { 
      nestFunc = func; 
      nestArgs = (args)...; // SO I CAN SET IT HERE 
     } 
     // Later I will forward this and run the function with its arguments 
     unsigned process() { 
      nestFunc(std::forward<Args>(nestArgs)...); // USE IT HERE 
      return 0; 
     } 
    }; 
    nest* myNest; 
    myNest->setup(func, (args)...); 
} 

Đây là một ví dụ về tất cả mọi thứ liên quan đến cho vấn đề, tôi cần lưu trữ các đối số cho sau gọi trong cấu trúc tổ của tôi. Ngoài ra, nếu bạn có một giải pháp để lưu trữ nó nhưng để thiết lập nó là khác nhau của tôi, xin vui lòng cũng cho tôi biết về điều đó quá. Cảm ơn.

+2

'std :: tuple '- cũng,' std :: bind' và 'std :: function' và tất cả những thứ thú vị đó. – Xeo

Trả lời

17

Bạn phải sử dụng ::std::tuple<Args...> để lưu trữ. Nhưng sau đó câu hỏi là làm thế nào để giải nén nó khi bạn cần nó. Cho rằng bạn cần sử dụng một kỹ thuật gọi là 'chỉ số'.

Vì vậy, đây là một liên kết đến một nơi mà tôi đã thực hiện gần như những gì bạn đang muốn làm. Lớp có liên quan nhất ở đây là loại trung tâm là suspended_call.

https://bitbucket.org/omnifarious/sparkles/src/tip/sparkles/deferred.hpp?at=default

Chỉ trong một chút, tôi sẽ trích xuất các bit phù hợp nhất và đặt chúng về mã của bạn.

This line:

auto saved_args = ::std::make_tuple(::std::move(args)...); 

tiết kiệm các đối số vào một tuple. Tôi đã sử dụng ::std::move ở đó và tôi nghĩ đó là điều phải làm. Nhưng có thể tôi sai và tôi nên sử dụng ::std::forward. Tôi chưa bao giờ rõ ràng về sự khác biệt chính xác ngoài ý định báo hiệu.

Mã thực sự thực hiện cuộc gọi với các đối số đã lưu có thể được tìm thấy here. Bây giờ mã đó khá cụ thể cho chính xác những gì tôi đang làm. Bit thực hiện thủ thuật chỉ mục liên quan đến việc tạo một gói các số nguyên ánh xạ tới các chỉ mục để sử dụng làm đối số mẫu ::std::get<I>. Một khi bạn có gói số nguyên này, bạn có thể sử dụng nó để mở rộng cuộc gọi đến ::std::get để nhận tất cả các phần tử tuple dưới dạng đối số riêng lẻ.

tôi sẽ cố gắng đưa ra với mã nào đó theo một cách tương đối đơn giản:

#include <tuple> 
#include <cstddef> 
#include <string> 
#include <utility> 

template < ::std::size_t... Indices> 
struct indices {}; 

template < ::std::size_t N, ::std::size_t... Is> 
struct build_indices : build_indices<N-1, N-1, Is...> 
{}; 

template < ::std::size_t... Is> 
struct build_indices<0, Is...> : indices<Is...> 
{}; 

template <typename FuncT, typename ArgTuple, ::std::size_t... Indices> 
auto call(const FuncT &f, ArgTuple &&args, const indices<Indices...> &) 
    -> decltype(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...)) 
{ 
    return ::std::move(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...)); 
} 

template <typename FuncT, typename ArgTuple> 
auto call(const FuncT &f, ArgTuple &&args) 
    -> decltype(call(f, args, 
         build_indices< ::std::tuple_size<ArgTuple>::value>{})) 
{ 
    const build_indices< ::std::tuple_size<ArgTuple>::value> indices; 

    return ::std::move(call(f, ::std::move(args), indices)); 
} 

int myfunc(::std::string name, const unsigned int foo) 
{ 
    return 0; 
} 

int foo(::std::tuple< ::std::string, const unsigned int> saved_args) 
{ 
    return call(myfunc, ::std::move(saved_args)); 
} 

Rất nhiều mã này được mượn từ this page on the indices trick.

Ngoài ra, đó là một mẫu mà bạn sẽ phải điều chỉnh một chút cho tình huống cụ thể của bạn. Về cơ bản, chỉ cần gọi call(nestFunc, saved_args) ở đâu đó.

+0

Làm thế nào để thiết lập tuple này với (args) ...; – Luka

+1

Bạn có thể giải thích thêm về các "chỉ báo" này không? – 0x499602D2

+0

@David: Có, nhiều ví dụ hơn. Bạn sẽ có chúng. Tôi thực sự đã phải viết mã đã làm điều này gần đây. – Omnifarious

4

Tôi biết nó được một lúc nhưng tôi có nhu cầu tương tự và đã đưa ra giải pháp này, hy vọng nó sẽ giúp ai đó:

#include <functional> 

template<typename Func, typename... Args> 
struct nest { 
    std::function<void()> callBack; 

    void setup(Func func1, Args... args) { 
     callBack = [func1, args...]() 
     { 
      (func1)(args...); 
     }; 
    } 

    unsigned process() { 
     callBack(); 
     return 0; 
    } 
}; 

template<typename Func, typename... Args> 
void handleFunc(Func func, Args&&... args) { 
    nest<Func, Args...> myNest; 
    myNest.setup(func, args...); 
} 
+0

giải pháp thông minh cho cú pháp gói C++ bị tê liệt điên rồ) –

+0

Lưu trữ tất cả chúng bên trong một lambda thay vì trong một tuple là rất thông minh. – Omnifarious

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