2016-08-24 2 views
0

Puis-je transmettre un pointeur de fonction "général" en tant qu'argument de modèle avec sa signature? Je sais que je peux passer la signature de fonction à un modèle:Pointeur de fonction en tant qu'argument modèle et signature

template<typename signature> 
struct wrapper; 

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

int f(int, double) 

wrapper<decltype(f)> w; 

Je peux aussi passer un pointeur de fonction comme un argument de modèle non type:

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

    myTemp<f>(); 

Ce que je voudrais faire est quelque chose comme ceci

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

Est-ce possible? Le pointeur de fonction doit être passé en tant qu'argument de modèle et ne doit pas être passé en tant que paramètre de fonction. Je souhaite utiliser le modèle pour envelopper les fonctions c et les rendre appelables à partir de lua. Le code suivant fonctionne (C++ 14, gcc, lua-5.3), mais pourrait être amélioré.

#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

Je lis [pointeur _function comme modèle argument_] (http://stackoverflow.com/search ? q =% 5Bc% 2B% 2B% 5Donction + pointeur + as + modèle + paramètre) environ cinq à sept fois par semaine (si ce n'est plus souvent) ici. Bien sûr, vous ne pouvez pas trouver d'informations primaires, qui sont déjà disponibles? –

+0

Je n'avais pas ce que 'myTemp()' est supposé être. Peut-être que vous manquez un type de retour? –

+0

@ πάνταῥεῖ J'ai cherché le pointeur de fonction comme argument de modèle, mais tout ce que j'ai trouvé sont les deux premiers cas, et pas le troisième auquel je suis intéressé. Si vous avez un lien concernant ce cas, je serais reconnaissant. – Robin

Répondre

0

C++ 17 permettrait

template <auto value> struct wrapper; 

et votre spécialisation

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

et utilisation:

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

Avant C++ 1Z, votre wrapper a être

template <typename Sig, sig Pf> struct wrapper; 

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

qui vous oblige à répéter le nom de la fonction (si vous ne tapez pas manuellement sa signature)

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

De toute façon, la question n'a pas la balise _c1z_, donc je suppose que cela ne répond pas vraiment. Ai-je tort? – skypjack

+0

@skypjack: pre-C++ 1z, cette syntaxe n'est pas supportée, donc pour vraiment répondre à la question de l'OP, non il n'est pas possible d'utiliser une syntaxe similaire. – Jarod42

+0

Eh bien, celui-là (_no, ce n'est pas possible_) serait une réponse en effet. Ensuite, ajouter des informations sur les fonctionnalités à venir enrichit la réponse, bien sûr. :-) – skypjack