2016-08-28 3 views
5

Ich habe eine Typliste. Ich möchte ein Tupel mit den Ergebnissen des Aufrufs einer Funktion für jeden Typ in dieser Liste erstellen und diese dann als Argumente für einen anderen Funktor verwenden. So etwas wie folgt aus:Transform Typliste mit Funktion zur Laufzeit

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

Das Problem ist, dass func(*get_arg<param_types>(id)...); eigentlich nicht, da param_types zu kompilieren ist ein Tupel und kein Parameter Pack. Der Compiler generiert diesen Fehler: "Es sind keine Parameterpakete zum Erweitern verfügbar". Was würde ich gern geschehen sein ist für diese Linie zu erweitern:

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

Und dass die Arbeit für eine beliebige Anzahl von Argumenten zu haben. Gibt es eine Möglichkeit, dieses Ergebnis zu erhalten?

Diese Frage scheint ähnlich, löst aber nicht mein Problem selbst: "unpacking" a tuple to call a matching function pointer. Ich habe eine Typenliste und möchte daraus eine Liste von Werten generieren, die als Funktionsargumente verwendet werden. Wenn ich die Liste der Werte hätte, könnte ich sie erweitern und die Funktion wie in dieser Frage beschrieben aufrufen, aber ich tue es nicht.

+0

Wie lautet das erwartete Ergebnis des Aufrufs von 'func' in' call_func'? Dass alle Argumente gleich "id" sein sollten? In Ihrem Beispiel 'call_func ([] (int & a, char & b) {}, 3)' was wird das Argument o das Lambda sein? –

+0

Der ID-Parameter ist nicht wirklich wichtig. In meinem Anwendungsfall verwende ich es innerhalb von get_arg, um herauszufinden, welche Instanz von T zurückgegeben werden soll. Die Argumente für das Lambda wären hoffentlich die Ergebnisse des Aufrufs von get_arg für jeden Typ in der Typliste, ähnlich wie oben geschrieben: 'func (* get_arg (id), * get_arg (id));' –

+0

Mögliches Duplikat von ["entpacken" ein Tupel, um einen passenden Funktionszeiger aufzurufen] (http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer) – TFM

Antwort

1

Nicht sicher, dass was Sie wollen.

Ich weiß nicht, wie zu erweitern, innerhalb call_func(), die Parameter Packung von params_type aber, wenn Sie die Verwendung eines Helfer-Struktur und einen Compiler mit C++ 14 ...

ich leisten haben bereitete das folgende Beispiel mit Unterstützung für Rückgabetyp vor.

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

Hoffe das hilft.

+0

Schön!Ich muss meinen Kopf einwickeln, aber ich denke, das tut alles, was ich brauche. Ich bin (angenehm) überrascht, dass Sie '>' als Spezialisierung für das Lambda verwenden können? Ich hätte gedacht, dass es aussehen müsste wie die hässlichere 'R (T :: *) (Args ...) const' Spezialisierung auf' function_traits'. –

Verwandte Themen