2016-08-28 21 views
5

Tôi có một typelist. Tôi muốn tạo một tuple với các kết quả gọi một hàm trên mỗi kiểu trong danh sách đó và sau đó sử dụng nó như các đối số cho một hàm khác. Vì vậy, một cái gì đó như thế này:Biến typelist có chức năng tại thời gian chạy

template<typename F> 
struct function_traits; 

template<typename T, typename R, typename... Args> 
struct function_traits<R(T::*)(Args...) const> { 
    using return_type = R; 
    using param_types = std::tuple<Args...>; 
}; 

template<typename T> struct function_traits : public 
function_traits<decltype(&T::operator())> {}; 

template <typename T> 
T* get_arg(int id) 
{ 
    // Actual implementation omitted. Uses the id parameter to 
    // do a lookup into a table and return an existing instance 
    // of type T. 
    return new T(); 
} 

template <typename Func> 
void call_func(Func&& func, int id) 
{ 
    using param_types = function_traits<Func>::param_types>; 

    func(*get_arg<param_types>(id)...); // <--- Problem is this line 
} 

call_func([](int& a, char& b) { }, 3); 

Vấn đề là func(*get_arg<param_types>(id)...); không thực sự biên dịch từ param_types là một tuple và không phải là một gói tham số. Trình biên dịch tạo ra lỗi này: "không có gói tham số có sẵn để mở rộng". Điều tôi muốn xảy ra là để dòng đó mở rộng tới:

func(*get_arg<int>(id), *get_arg<char>(id)); 

Và để làm việc đó cho bất kỳ số đối số nào. Có cách nào để có được kết quả đó không?

Câu hỏi này có vẻ tương tự nhưng không tự giải quyết được vấn đề của tôi: "unpacking" a tuple to call a matching function pointer. Tôi có một danh sách kiểu và từ đó tôi muốn tạo ra một danh sách các giá trị để sử dụng như các đối số hàm. Nếu tôi có danh sách các giá trị tôi có thể mở rộng chúng và gọi hàm như được nêu trong câu hỏi đó, nhưng tôi thì không.

+0

Kết quả mong đợi của cuộc gọi đến 'func' bên trong' call_func' là gì? Tất cả các đối số phải bằng 'id'? Trong ví dụ của bạn 'call_func ([] (int & a, char & b) {}, 3)' đối số của lambda sẽ là gì? –

+0

Thông số id không thực sự quan trọng. Trong trường hợp sử dụng của tôi, tôi sử dụng nó trong get_arg để tìm ra trường hợp T nào để trả về. Các đối số cho lambda hy vọng sẽ là kết quả gọi get_arg cho mỗi loại trong typelist, tương tự như những gì tôi đã viết ở trên: 'func (* get_arg (id), * get_arg (id)); ' –

+0

["giải nén" một bộ dữ liệu để gọi một con trỏ hàm phù hợp] (http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer) – TFM

Trả lời

1

Không chắc chắn đó là những gì bạn muốn.

Tôi không biết làm thế nào để mở rộng, bên trong call_func(), các thông số gói params_type nhưng, nếu bạn đủ khả năng sử dụng một struct helper và một trình biên dịch với C++ 14 ...

Tôi đã chuẩn bị ví dụ sau với sự hỗ trợ cho kiểu trả về.

#include <tuple> 

template<typename F> 
struct function_traits; 

template<typename T, typename R, typename... Args> 
struct function_traits<R(T::*)(Args...) const> { 
    using return_type = R; 
    using param_types = std::tuple<Args...>; 
}; 

template<typename T> struct function_traits : public 
function_traits<decltype(&T::operator())> {}; 

template <typename T, typename ... Args> 
T get_arg (std::tuple<Args...> const & tpl) 
{ return std::get<typename std::decay<T>::type>(tpl); } 

template <typename ...> 
struct call_func_helper; 

template <typename Func, typename Ret, typename ... Args> 
struct call_func_helper<Func, Ret, std::tuple<Args...>> 
{ 
    template <typename T, typename R = Ret> 
     static typename std::enable_if<false == std::is_same<void, R>::value, R>::type 
       fn (Func const & func, T const & t) 
     { return func(get_arg<Args>(t)...); } 

    template <typename T, typename R = Ret> 
     static typename std::enable_if<true == std::is_same<void, R>::value, R>::type 
       fn (Func const & func, T const & t) 
     { func(get_arg<Args>(t)...); } 
}; 

template <typename Func, 
      typename T, 
      typename R = typename function_traits<Func>::return_type> 
R call_func (Func const & func, T const & id) 
{ 
    using param_types = typename function_traits<Func>::param_types; 

    return call_func_helper<Func, R, param_types>::fn(func, id); 
} 

int main() 
{ 
    call_func([](int const & a, char const & b) { }, std::make_tuple(3, '6')); 

    return 0; 
} 

Hy vọng điều này sẽ hữu ích.

+0

Rất tuyệt!Tôi phải quấn đầu xung quanh nhưng tôi nghĩ điều này làm mọi thứ tôi cần. Tôi (ngạc nhiên) ngạc nhiên khi bạn có thể sử dụng '>' như là một chuyên môn cho lambda? Tôi đã có thể nghĩ rằng nó sẽ cần phải trông giống như ug '' '' (T :: *) (Args ...) const 'chuyên môn trên 'function_traits'. –

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