2016-08-24 5 views
0

Kann ich passiere einen „allgemeinen“ Funktionszeiger als Template-Argument mit ihm ist die Signatur? Ich weiß, dass ich die Funktion Signatur zu einer Vorlage passieren kann:Funktionszeiger als Template-Argument und Unterschrift

template<typename signature> 
struct wrapper; 

template<typename RT, typename... ATs> 
struct wrapper<RT (ATs...)> {}; 

int f(int, double) 

wrapper<decltype(f)> w; 

Ich kann auch einen Funktionszeiger als nicht-Typ Template-Argument übergeben:

template<int (*pF)(int, double)> myTemp() { 
     pf(1, 1.0); 
    } 

    myTemp<f>(); 

Was ich möchte, ist, etwas zu tun so

template<typename RT (*pF)(typename ATs...)> 

Ist das möglich? Der Funktionszeiger muss als Vorlageargument übergeben werden und darf nicht als Funktionsparameter übergeben werden.

Ich möchte die Vorlage verwenden, um C-Funktionen zu umhüllen und sie von lua aufrufbar machen. Der folgende Code funktioniert (C++ 14, gcc, lua-5.3), könnte aber verbessert werden.

#include <iostream> 
#include <type_traits> 

extern "C" { 
#include <lua.h> 
#include <lualib.h> 
#include <lauxlib.h> 
} 

using namespace std; 

int add(int i, int j) { 
    cout << "adding " << i << " to " << j << "." << endl; 
    return i + j; 
} 

int sub(int i, int j) { 
    cout << "subtracting " << j << " from " << i << "." << endl; 
    return i - j; 
} 

// **************************** 

template<typename signature> 
struct wrapper; 

template<typename RT, typename... ATs> 
struct wrapper<RT (ATs...)> { 

    template<RT (*pF)(ATs...)> 
    void reg(lua_State *L, const char*n) { 
     auto lw = [](lua_State *L) -> RT { 
      lua_pushnumber(L, call<0>(pF, L)); 
      return 1; 
     }; 
     lua_pushcfunction(L, lw); 
     lua_setglobal(L, n); 
    } 

    template<int i, typename... ETs> 
    static 
    typename std::enable_if<i != sizeof...(ATs), RT>::type 
    call(RT (*f)(ATs...), lua_State *L, ETs... Es) { 
     auto arg = lua_tonumber(L, i+1); 
     return call<i+1>(f, L, Es..., arg); 
    } 

    template<int i, typename... ETs> 
    static 
    typename std::enable_if<i == sizeof...(ATs), RT>::type 
    call(RT (*f)(ATs...), lua_State *L, ETs... Es) { 
     return f(Es...); 
    } 

}; 

#define regLua(L, fct, str) wrapper<decltype(fct)>().reg<fct>(L, str) 

int main() { 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 

    luaL_dostring(L, "print(\"Hello World!\")"); 

    // Ugly: add must be passed two times! Not a very userfriendly syntax. 
    wrapper<decltype(add)>().reg<add>(L, "add"); 
    // Looks better, but uses a macro... 
    regLua(L, sub, "sub"); 
    // optimal (but possible??): 
    // wrap<sub>(L, "sub"); 

    luaL_dostring(L, "print(\"add:\", add(3, 5))"); 
    luaL_dostring(L, "print(\"sub:\", sub(3, 5))"); 

    lua_close(L); 

    return 0; 
} 
+3

Ich lese [_function Zeiger als Vorlage argument_] (http://stackoverflow.com/search ? q =% 5Bc% 2B% 2B% 5Dfunktion + Zeiger + als + Schablone + Parameter) etwa fünf bis sieben Mal pro Woche (wenn nicht häufiger) hier. Sicher, Sie können keine primäre Information finden, die bereits verfügbar ist? –

+0

Ich habe nicht bekommen, was 'myTemp()' sein soll. Vielleicht vermisst du einen Rückgabetyp? –

+0

@ πάνταῥεῖ ich für Funktionszeiger als Template-Argument gesucht, aber alles, was ich gefunden sind die ersten beiden Fällen und nicht die dritte, in dem ich interessiert bin. Wenn Sie einen Link zu diesem Fall haben, wäre ich dankbar. – Robin

Antwort

0

C++ 17

template <auto value> struct wrapper; 

erlauben würde, und dann Spezialisierung

template<typename RT, typename... ATs, RT (*pF)(ATs...)> 
struct wrapper<pF> { 
    static void reg(lua_State *L, const char* n) { 
     auto lw = [](lua_State *L) { 
      lua_pushnumber(L, call(L, std::index_sequence_for<ATS...>())); 
      return 1; 
     }; 
     lua_pushcfunction(L, lw); 
     lua_setglobal(L, n); 
    } 

    template<std::size_t ... Is> 
    static 
    RT call(lua_State *L, std::index_sequence<Is...>) { 
     return pF(lua_tonumber(L, 1 + Is)...); 
    } 
}; 

Und Nutzung:

wrapper<&add>::reg(L, "add"); 

Vor C++ 1z, Ihre wrapper hat zu sein

template <typename Sig, sig Pf> struct wrapper; 

template<typename RT, typename... ATs, RT (*pF)(ATs...)> 
struct wrapper<Rt (*)(ATS...), pF> { 
    // Code 
}; 

, die zwingt Sie die Funktionsnamen zu wiederholen (wenn Sie nicht manuell tun, um seine Unterschrift geben)

wrapper<decltype(&add), &add>::reg(L, "add"); 
+0

Wie auch immer, die Frage hat nicht das _c1z_ Tag, also denke ich, das beantwortet es nicht wirklich. Liege ich falsch? – skypjack

+0

@skypjack: pre-C++ 1z, dass Syntax nicht unterstützt wird, so wirklich zu OPs Frage zu beantworten, nein, es ist nicht möglich, ähnliche Syntax zu verwenden. – Jarod42

+0

Nun, dieser (nein, es ist nicht möglich) wäre in der Tat eine Antwort. Das Hinzufügen von Informationen zu den kommenden Funktionen bereichert die Antwort natürlich. :-) – skypjack

Verwandte Themen