Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

functions as template argument, plus variadic template argument

Tags:

c++

c++11

I'm writing a generalized function wrapper, that can wrap any function into a lua-style call, which has the form

int lua_function( lua_State *L)

And I wish the wrapper function is generated on-the-fly, so I'm thinking of passing the function as a template argument. This is trivial if you know the number (e.g, 2) of arguments:

template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)>
struct wrapper

However, I don't know the number, so I beg for variadic template argument for help

// This won't work
template <typename R, typename... Args, R F(Args...)>
struct wrapper

The above won't compile, since variadic argument has to be the last one. So I use two level template, the outer template captures types, the inner template captures the function:

template <typename R, typename... Args>
struct func_type<R(Args...)>
{
  // Inner function wrapper take the function pointer as a template argument
  template <R F(Args...)>
  struct func
  {
    static int call( lua_State *L )
    {
      // extract arguments from L
      F(/*arguments*/);
      return 1;
    }
  };
};

That works, except that to wrap a function like

double sin(double d) {}

the user has to write

func_type<decltype(sin)>::func<sin>::apply

which is tedious. The question is: is there any better, user-friendlier way to do it? (I can't use a function template to wrap the whole thing, coz a function parameter can't be used as a template argument.)

like image 628
Ralph Zhang Avatar asked May 16 '11 11:05

Ralph Zhang


People also ask

How do you write a variadic function in C++?

Variadic functions are functions (e.g. std::printf) which take a variable number of arguments. To declare a variadic function, an ellipsis appears after the list of parameters, e.g. int printf(const char* format...);, which may be preceded by an optional comma.

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.

How do you use variadic arguments?

It takes one fixed argument and then any number of arguments can be passed. The variadic function consists of at least one fixed variable and then an ellipsis(…) as the last parameter. This enables access to variadic function arguments. *argN* is the last fixed argument in the variadic function.


1 Answers

Things like std::function and std::result_of use the following technique to do what you want regarding variadic templates:

template<typename Signature>
struct wrapper; // no base template

template<typename Ret, typename... Args>
struct wrapper<Ret(Args...)> {
    // instantiated for any function type
};

You could expand the above to add a non-type Ret(&P)(Args...) template parameter (pointers to function work just as well) but you'd still need a decltype at the user level, i.e. wrapper<decltype(sin), sin>::apply. Arguably it would be a legitimate use of the preprocessor if you decide to use a macro to remove the repetition.

template<typename Sig, Sig& S>
struct wrapper;

template<typename Ret, typename... Args, Ret(&P)(Args...)>
struct wrapper<Ret(Args...), P> {
    int
    static apply(lua_State*)
    {
        // pop arguments
        // Ret result = P(args...);
        // push result & return
        return 1;
    }
};

// &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function.

The above compiles with gcc-4.5 at ideone. Good luck with implementing the apply that (variadically) pops the arguments (leave me a comment if you open a question about that). Have you considered using Luabind?

like image 99
Luc Danton Avatar answered Nov 02 '22 23:11

Luc Danton