Metaprogrammierung: Function-Pointer @Compiletime
-
Hallo zusammen,
der Titel klingt zwar etwas komisch, allerdings würde ich gerne einer Template-Funktion übergeben, welche Funktion aufgerufen werden soll. Diese soll bereits zur Compiletime ausgewertet werden.
Also schematisch etwa so:
template<typename T> void call(const T& t, <functionName>){ t.<functionName>(); }Der Code soll nur verdeutlichen, was ich eigentlich möchte und kann natürlich nicht ansatzweise so funktionieren.
Zur Zeit verwende ich zur Verwirklichung dieses Problems
folgenden Ansatz (hier auch mit zusätzlichen Parametern für den Funktionsaufruf):#include <iostream> struct Foo{ void foo(int i) const{ std::cout << "Foo::foo int" << std::endl; } void foo(double i) const{ std::cout << "Foo::foo double" << std::endl; } void foo(int i, int j) const{ std::cout << "Foo::foo 2*int" << std::endl; } void bar() const{ std::cout << "Foo::bar" << std::endl; } }; struct Bar{ void foo(int i) const{ std::cout << "Bar::foo int" << std::endl; } void foo(double d) const{ std::cout << "Bar::foo double" << std::endl; } void bar() const{ std::cout << "Bar::bar" << std::endl; } }; template<typename T> struct CallFoo{ template<typename... P> static void call(const T& t, P&&... p){ t.foo(std::forward<P>(p)...); } }; template<typename T> struct CallBar{ static void call(const T& t){ t.bar(); } }; template<template<typename> class Func, typename T, typename... P> void call(const T& t, P&&... p){ Func<T>::call(t, std::forward<P>(p)...); } int main(){ Foo foo; Bar bar; call<CallFoo>(foo, 1); call<CallFoo>(foo, 1.0); call<CallFoo>(foo, 1, 1); call<CallBar>(foo); call<CallFoo>(bar, 1); call<CallFoo>(bar, 1.0); call<CallBar>(bar); }Hier sieht man auch, dass einfache Funktionszeiger nicht mehr ausreichen...
Geht es evtl. eleganter oder habt ihr Alternativvorschläge?
Gruß,
XSpille
-
Ich kann an dem Beispiel nicht erkennen, was du eigentlich erreichen möchtest.
XSpille schrieb:
der Titel klingt zwar etwas komisch, allerdings würde ich gerne einer Template-Funktion übergeben, welche Funktion aufgerufen werden soll. Diese soll bereits zur Compiletime ausgewertet werden.
Also schematisch etwa so:
template<typename T> void call(const T& t, <functionName>){ t.<functionName>(); }Meinst du vielleicht so etwas?
template<typename T, typename F> void call(const T& t, const F& function){ function(t); } struct Type { void method() const; }; Type object; call(object, std::bind(&Type::method, _1));
-
XSpille schrieb:
Diese soll bereits zur Compiletime ausgewertet werden.
Die Funktion? Das geht nicht. Du kannst den Compiler so nicht zwingen, etwas zur Compilezeit auszuwerten, was kein konstanter Ausdruck ist. Dafür gibt es allerdings constexpr.
-
@TyRoXx: Okay... Dann hol ich mal etwas weiter aus...
Ich möchte im Endeffekt eine Funktion habentemplate<typename...T, typename... P> void call(std::tuple<T...> tuple, std::tuple<P...> parameter, <funcName>);die folgende Funktionen aufruft:
std::get<0>(tuple).<funcName>(std::get<0>(parameter)); // ... std::get<n>(tuple).<funcName>(std::get<n>(parameter));Dabei reicht mir ein std::bind (denke ich) nicht aus,
da ich es auf unterschiedlichen Objekt-Typen mit unterschiedlichen Parameter-Typen ausführe.@cooky451: Das war natürlich falsch ausgedrückt. Ich wollte sagen, dass die Funktionsauswahl - foo(int) oder foo(double) - schon zur Compilezeit aufgewertet werden soll.
-
template<typename...T, typename... P, typename F> void call(std::tuple<T...> tuple, std::tuple<P...> parameter, const F &function) { function( std::get<0>(tuple), std::get<0>(parameter)); // ... } struct func_abc { template <class T, class P> void operator ()(const T &t, const P &p) { t.abc(p); } }; call(.., .., func_abc());Also ungefähr das?
-
Genau...
DANKE TyRoXx!
Gefällt mir wesentlich besser als mein Vorschlag.
Gruß,
XSpille
-
Sieht mir nach einer natürlichen Anwengung für boost::fusion aus. Schau mal, ob da nicht bereits implementiert ist, was du brauchst
-
XSpille schrieb:
std::get<0>(tuple).<funcName>(std::get<0>(parameter)); // ... std::get<n>(tuple).<funcName>(std::get<n>(parameter));Das geht nur, wenn die Elemente beider tupels vom gleichen Typ sind, weil sonst <funcName> zwar immer der gleiche Name, aber immer eine völlig andere Funktion ist.
Falls es so ist, machen tupel eigentlich keinen Sinn, sondern eher std::array oder sowas.
Falls es nicht so ist, müsstest du ein template für jeden Funktionsnamen bereitstellen, etwa wie folgt:
template <class T, class P> struct callMemFoo { void operator()(T& t, P& p) { t.foo(p); } }; template < template<class, class> class F, typename... T, typename... P> void call(std::tuple<T...> ts, std::tuple<P...> ps);Implementiert sähe die call-Funktion dann so aus:
#include <tuple> template <typename T, typename P, template<class, class> class F, unsigned N> struct do_call { void operator()(T& t, P& p) { const static unsigned Pos = std::tuple_size<T>::value - N; auto f = F<typename std::tuple_element<Pos,T>::type, typename std::tuple_element<Pos,P>::type>(); f(std::get<Pos>(t), std::get<Pos>(p)); do_call<T, P, F, N-1> call_next; call_next(t, p); } }; template <typename T, typename P, template<class, class> class F> struct do_call<T, P, F, 0> { void operator()(T&, P&){} }; template < template<class, class> class F, typename... T, typename... P> void call(std::tuple<T...> ts, std::tuple<P...> ps) { static_assert(sizeof...(T) == sizeof...(P), "T and P tuples must have same size"); do_call<std::tuple<T...>, std::tuple<P...>, F, sizeof...(T)> call_first; call_first(ts, ps); }Läuft unter GCC, Beispiel: http://ideone.com/WBPjk
-
Danke otze, werde ich mir heute abend in Ruhe mal angucken.
Danke pumuckl, wie ich es ansonsten verwirkliche ist mir klar.
Ich erstelle mir Indizes, dann kann ich auch Rückgabewerte einfach wieder in ein Tupel packen.Es sollen unterschiedliche Typen sein, die gewisse Funktionen haben (somit unterschiedliche Funktionen).