2016-08-28 14 views
5

Mam typelistę. Chciałbym utworzyć krotkę z wynikami wywołania funkcji dla każdego typu na tej liście, a następnie użyć jej jako argumentów dla innego funktora. Więc coś takiego:Przekształć typelistę z funkcją w czasie wykonywania

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

Problemem jest to, że func(*get_arg<param_types>(id)...); faktycznie nie skompilować od param_types jest krotka, a nie paczka parametr. Kompilator generuje ten błąd: "nie ma dostępnych pakietów parametrów do rozwinięcia". To, co chciałbym mieć, to rozszerzenie tej linii na:

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

I wykonanie tej pracy dla dowolnej liczby argumentów. Czy istnieje sposób na uzyskanie tego wyniku?

To pytanie wydaje się podobne, ale samo w sobie nie rozwiązuje problemu: "unpacking" a tuple to call a matching function pointer. Mam listę typów i na podstawie tego chcę wygenerować listę wartości do użycia jako argumenty funkcji. Gdybym miał listę wartości, mógłbym je rozwinąć i zadzwonić do funkcji przedstawionej w tym pytaniu, ale ja nie.

+0

Jaki jest oczekiwany rezultat połączenia z 'func' wewnątrz' call_func'? Że wszystkie argumenty powinny być równe "id"? W twoim przykładzie 'call_func ([] (int & a, char & b) {}, 3)' jaki będzie argument o lambda? –

+0

Parametr id nie jest tak naprawdę ważny. W moim przypadku użycia używam go wewnątrz get_arg, aby dowiedzieć się, które wystąpienie T, aby powrócić. Argumentami dla lambdy mogą być wyniki wywołania get_arg dla każdego typu w liście typów, podobne do tego, co napisałem powyżej: 'func (* get_arg (id), * get_arg (id));' –

+0

Możliwy duplikat ["rozpakowywanie" krotki, aby wywołać odpowiedni wskaźnik funkcji] (http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer) – TFM

Odpowiedz

1

Nie jestem pewien, czy tego chcesz.

nie wiem, jak się rozwijać, wewnątrz call_func(), pakiet parametrów params_type, ale jeśli sobie pozwolić na wykorzystanie struct pomocnika i kompilatora C++ z 14 ...

mam przygotował następujący przykład ze wsparciem dla typu zwrotu.

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

Mam nadzieję, że to pomoże.

+0

Nice!Muszę to objąć, ale myślę, że robi to wszystko, czego potrzebuję. Jestem (mile) zaskoczony, że możesz używać '>' jako specjalizacji dla lambda? Pomyślałbym, że musiałby wyglądać jak brzydsza 'R (T :: *) (Args ...) const' specjalizacja na' function_traits'. –

Powiązane problemy