Creating a tuple of data and sending unpacked as a function arguements - c++

Hi I was wonder if anyone could help me with this. I'm trying to implement the CallFunction (the bit with the comment in). I'm not sure how to go about doing it.
[Question] I want to create a tuple of types created from the ...Arguments, but I want to
strip the qualifiers, const, &, etc, so then I can fill it up with my data and somehow pass onward to the function.
Im not bothered with the return type for now. Anyone point me in the right direction or have done something similar? Or is it completely crazy and not something that can be done. HMM! Anyway TY for checking it out :)
template <typename This, typename Func> class ForwardFunction
{
private:
template <typename Object, typename Return, typename ...Arguments> struct info_base
{
enum { nargs = sizeof...(Arguments) };
typedef Return return_type;
typedef std::tuple<Arguments...> arg_list_type;
template <size_t index> struct arg
{
typedef typename std::tuple_element<index, std::tuple<Arguments...>>::type type;
};
template <int argCount> static void CallFunction(Func function, CLuaHelper & helper, lua_State *pState)
{
/*
// temp - pseudo
arg_list_type argList;
for (int i = 0; i < argCount; ++i)
std::get<0>(argList) = helper.Get<arg<i>::type>(pState);
(This::GetThis(pState)->*(function))(argList...);
*/
}
template <> static void CallFunction<0>(Func function, CLuaHelper & helper, lua_State *pState)
{
(This::GetThis(pState)->*(function))();
}
static void Call(Func function, CLuaHelper & helper, lua_State *pState)
{
CallFunction<nargs>(function, helper, pState);
}
};
template <typename Func> struct info;
template <typename Object, typename Return, typename ...Arguments> struct info<std::function<Return (Object::*)(Arguments...)>> : info_base<Object, Return, Arguments...> { };
template <typename Object, typename Return, typename ...Arguments> struct info<std::function<Return (Object::*)(Arguments...) const>> : info_base<Object, Return, Arguments...> { };
public:
static int ForwardCall(Func function, lua_State *pState)
{
CLuaHelper helper(pState);
info<std::function<Func>>::Call(function, helper, pState);
return helper.ReturnValues();
}
};
Its used with
#define __LUA_FUNCTION_CALL [&](lua_State *pState) -> int
#define __LUA_INSTANT_ACCESS_CALL(name) \
{ #name, __LUA_FUNCTION_CALL { return ForwardFunction<CComponentScript, decltype(&CComponent::##name)>::ForwardCall(&CComponent::##name, pState); } }
const CLuaHelper::function_list CComponentScript::m_sRegisterFunctions[] =
{
__LUA_INSTANT_ACCESS_CALL(SetOnLoad),
__LUA_INSTANT_ACCESS_CALL(SetOnEvent),
__LUA_INSTANT_ACCESS_CALL(SetOnUpdate),
__LUA_INSTANT_ACCESS_CALL(SetOnClose),
__LUA_INSTANT_ACCESS_CALL(RegisterEvent),
__LUA_INSTANT_ACCESS_CALL(SetBasePriority),
{nullptr, nullptr}
};

I assume, you mean to assign the values with the corresponding index rather than always assigning to the 0 index inside the loop. The basic approach to call a function with the elements of a std::tuple<...> is rather straight forward assuming you have an implementation of std::integer_sequence (which is part of C++14):
template <int... N, typename... T>
void call_aux(std::integer_sequence<int, N...>, std::tuple<T...>&& value)
{
print(std::get<N>(value)...);
}
template <typename Tuple>
void call(Tuple&& value)
{
call_aux(std::make_integer_sequence<int, std::tuple_size<std::decay_t<Tuple>>::value>(),
std::forward<Tuple>(value));
}
The basic idea is that std::make_integer_sequence<...> creates a suitable sequence of integers. Once you got this, you can also add a corresponding operation fill the a std::tuple<...> with the values based on your pState. The logic to actually fill the std::tuple<...> could look something like this (I don't have Lua installed, i.e., I can't test whether this actually works but something like this does work):
template <int I, typename Tuple>
bool assign_helper2(Tuple& tuple, lua_Helper& helper, lua_State* pState) {
std::get<I>(tuple) = helper.Get<arg<I>::type>(pState);
}
template <typename... T>
void dummy(T&&...) {
}
template <int I, typename Tuple>
void assign_helper1(std::integer_sequence<int, I...>, Tuple& tuple,
lua_Helper& helper, lua_State* pState) {
dummy(assign_helper2<I>(tuple, helper, pState)...);
}
template <typename Tuple>
void assign(Tuple& tuple, lua_Helper& helper, lua_State* pState) {
assign_helper1(std::make_integer_sequence<int, std::tuple_size<std::decay_t<Tuple>>::value>(),
tuple, helper, pState);
}
Although the code uses C++14 functionality, the corresponding classes can be implemented using C++11. The implementation is fairly straight forward. Here is an implementation implementing the necessary integer generation using different names, though.

Related

std::tuple of std::shared_ptr of template parameter pack

I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.

Error when trying to expand template parameter pack

I'm trying to use variadic templates to store the parameter types to a member function. The way I'm trying to achieve this is by associating each type with a key, then storing this key in an std::vector. The code for creating this key is as follows
template <typename T>
class ClassInfo {
public:
inline static void const* GetClassKey() {
static char key;
return &key;
}
};
Then I use the following code to try to store the keys in an std::vector
class WrappedMemberFunction {
void *function_pointer; // Holds the member function pointer
void const* class_type; // Class type key
void const* return_type; // Return type key
std::vector<void const*> parameter_types; // Parameter type keys
void StoreArguments() {}
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
StoreArguments<Args...>(); // Error here: No matching member function for call to 'StoreArguments'
}
public:
template <typename Class, typename ReturnType, typename... Args>
WrappedMemberFunction(ReturnType (Class::*member_pointer)(Args...)) {
// Store member pointer as regular old void pointer
function_pointer = (void*&)member_pointer;
// Store class type
class_type = ClassInfo<Class>::GetClassKey();
// Store return type
return_type = ClassInfo<Class>::GetClassKey();
// Store parameter types
StoreArguments<Args...>();
}
};
What I'm getting stuck on is the variadic recursion needed to store each class key. I am getting an error on the line indicated above, which is the recursive step in trying to expand the parameter pack. What am I doing wrong here?
You have:
// function that is not a template
void StoreArguments() {}
// function template that takes N+1 types
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
// call function template that takes N types
StoreArguments<Args...>();
}
Hopefully the comments I added make this clear... you're recursing from a function template taking N+1 types to a function template taking N types. The base case there is a function template taking 0 types. You don't have that, you have a nullary function - which won't be considered.
Your approaches are either to lift your types into values, so your base case actually is a nullary function:
template <class T> struct tag { using type = T; };
void StoreArgumentsImpl() { }
template <typename Arg, typename... Tags>
void StoreArgumentsImpl(tag<Arg>, Tags... tags) {
parameter_types.push_back(ClassInfo<Arg>::GetClassKey());
StoreArgumentsImpl(tags...);
}
template <typename... Args>
void StoreArguments() {
StoreArgumentsImpl(tag<Args>{}...);
}
Or do everything in a single function with the expander trick:
template <typename... Args>
void StoreArguments() {
using expander = int[];
(void)expander{0,
(void(
parameter_types.push_back(ClassInfo<Args>::GetClassKey())
), 0)...
};
}
Or, in C++17 (can't wait), with fold expressions:
template <typename... Args>
void StoreArguments() {
(parameter_types.push_back(ClassInfo<Args>::GetClassKey()), ...);
}
Or, also in C++17, with if constexpr (though this will not work with no arguments):
template <typename Arg, typename... Args>
void StoreArguments() {
parameter_types.push_back(ClassInfo<Args>::GetClassKey());
if constexpr(sizeof...(Args) > 0) {
StoreArguments<Args...>();
}
}

Using C++ variadic templates, how can I store a group of heterogeneously-typed objects AND iterate over them?

Suppose I have an object that is observable by other objects:
struct Object
{
struct Listener
{
virtual void fire() = 0;
}
Object(std::vector<Listener *> &listeners) :
listeners_(listeners)
{}
void fire()
{
for(auto *l : listeners_)
l->fire();
}
private:
std::vector<Listener *> listeners_;
};
Now, I would like to do the same thing using templates. Here's a skeleton of what I mean:
template<typename ... Listeners>
struct Object
{
Object(Listeners&&...listeners)
{
// How do I store each of the differently-typed references?
}
void fire()
{
// How do I iterate over the list of listeners?
}
};
Note that the key thing here is that I'm trying to avoid virtual function calls. I don't want my Listeners (in the templated code)to have to subclass a pure virtual class or anything like that.
I would advise against this. Your initial design seems great for having Observers - it decouples the two different parts of the design very well. Introducing templates means that everybody needs to know all the listeners that your Object holds. So make sure you really want to do this first.
That said, you're looking for a heterogeneous container of types - std::tuple. Storage is just:
template<typename... Listeners>
struct Object
{
std::tuple<Listeners...> listeners;
Object(Listeners const&... ls)
: listeners(ls...)
{ }
};
Firing involves the use of the index_sequence trick (this class was only introduced in C++14 but can be implemented using C++11). Here is a good answer explaining what is going on.
public:
void fire() {
fire(std::index_sequence_for<Listeners...>{});
}
private:
template <size_t... Is>
void fire(std::index_sequence<Is...> ) {
using swallow = int[];
(void)swallow{0,
(void(std::get<Is>(listeners).fire()), 0)...
};
}
With C++14 generic lambdas, it's easier to write a generic for_each_tuple:
template <class Tuple, class F, size_t... Is>
void for_each_tuple(Tuple&& tuple, F&& func, std::index_sequence<Is...> ) {
using swallow = int[];
(void)swallow{0,
(void(std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(tuple)))), 0)...
};
}
template <class Tuple, class F>
void for_each_tuple(Tuple&& tuple, F&& func) {
for_each_tuple(std::forward<Tuple>(tuple), std::forward<F>(func),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}
);
}
And now your fire() becomes:
void fire() {
for_each_tuple(listeners, [](auto& l) { l.fire(); });
}
You can use a std::tuple to store heterogeneous objects.
To iterate over it, here's some template magic. This will call the functor template for each object (thus, the functor will adapt to different types). SFINAE is used to determine when to stop the iteration. Variables From and To define the range, and on each iteration From is incremented. When they are equal, the iteration has to stop, so that's why there must be an empty function in that case.
#include <tuple>
#include <type_traits>
#include <cstddef>
template <template <typename> class Functor, typename Tuple, std::size_t From, std::size_t To>
typename std::enable_if<From == To, void>::type for_each(const Tuple &t) {}
template <template <typename> class Functor, typename Tuple, std::size_t From = 0, std::size_t To = std::tuple_size<Tuple>::value>
typename std::enable_if<From < To, void>::type for_each(const Tuple &t) {
Functor<typename std::tuple_element<From, Tuple>::type> op;
op(std::get<From>(t));
for_each<Functor, Tuple, From + 1, To>(t);
}
You need to write a functor template which you pass to it, like:
template <typename T>
struct Functor {
void operator()(const T &x) {
// ...
}
}
That will be called for each object.
In your code it would be something like this (not tested):
template <typename Listener>
struct FireFunctor {
void operator()(const Listener &x) {
x.fire();
}
}
template<typename ... Listeners>
struct Object
{
std::tuple<Listeners...> store;
Object(Listeners&&...listeners)
{
store = std::make_tuple(listeners...);
}
void fire()
{
for_each<FireFunctor>(store);
}
};

For loop over template arguments/types

I want to write benchmark code for several combinations of several possible classes. If I write each combination myself it becomes an unmaintainable mess. Thus I'm looking for a way to automatically combine each type via templates, something akin to the following pseudo code:
for (typename HashFuction : Sha256, Sha512, Sa512_256, Sha3_256, Sha3_512) {
for (typename KeyingWrapper : TwoPassKeyedHash, OnePassKeyedHash, PlainHash) {
for (typename InstantiatedGetLeaf: GetLeaf<8>, GetLeaf<1024>) {
for (typename algorithm : algA, algB, algC) {
runAndTime<HashFunction,KeyingWrapper,
InstantiatedGetLeaf,algorithm>(someArgs);
}
}
}
}
Where Sha256,… ,TwoPassKeyedHash,… are types.
The code I'm looking for is supposed to be functionally equivalent to the following:
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<8>,algA>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<8>,algB>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<8>,algC>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<1024>,algA>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<1024>,algB>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<1024>,algC>(someArgs);
runAndTime<Sha256,OnePassKeyedHash,GetLeaf<8>,algA>(someArgs);
runAndTime<Sha256,OnePassKeyedHash,GetLeaf<8>,algB>(someArgs);
runAndTime<Sha256,OnePassKeyedHash,GetLeaf<8>,algC>(someArgs);
// And 99 further lines…
With Peregring-lk's help I have come as far as
#include <iostream>
template<typename Aux_type>
void test_helper()
{}
template<typename Aux_type, typename Head, typename... Tail>
void test_helper() {
std::cout << Head::i;
test_helper<Aux_type, Tail...>();
}
template<typename... Args>
void test()
{
test_helper<void, Args...>();
}
struct A{
static const int i=1;
};
struct B{
static const int i=2;
};
int main() {
test<A, B>();
return 0;
}
but I don't yet see how I could iterate that recursion to get nested loops. Any help would be appreciated.
(Edit: Code restructuring and inclusion of Peregring-lk's answer.)
Sometimes it helps to have an idea of what you are aiming for:
you need several parameter types
and for each parameter types, several possible "values"
And want to apply something on every single combination of values (one per parameter type at a time).
This looks like it could be expressed:
combine<
Set<Sha256, Sha512, Sa512_256, Sha3_256, Sha3_512>,
Set<TwoPassKeyedHash, OnePassKeyedHash, PlainHash>,
Set<GetLeaf<8>, GetLeaf<1024>>,
Set<algA, algB, algC>
>(runAndTime);
if runAndTime is an instance of:
struct SomeFunctor {
template <typename H, typename W, typename L, typename A>
void operator()(cons<H>{}, cons<W>{}, cons<L>{}, cons<A>{});
};
and cons is just a way to pass a type as a regular parameter (much easier).
Let's go ?
First, some way to pass around types (cheaply):
template <typename T>
struct cons { using type = T; };
template <typename... T>
struct Set {};
An explicit bind (with no magic inside):
template <typename F, typename E>
struct Forwarder {
Forwarder(F f): inner(f) {}
template <typename... Args>
void operator()(Args... args) { inner(cons<E>{}, args...); }
F inner;
}; // struct Forwarder
And now we delve into the real task at hand:
we need to iterate on sets of types
within a set, we need to iterate on its elements (types too)
That calls for two levels of dispatch:
template <typename FirstSet, typename... Sets, typename F>
void combine(F func);
template <typename Head, typename... Tail, typename... Sets, typename F>
void apply_set(F func, Set<Head, Tail...>, Sets... others);
template <typename... Sets, typename F>
void apply_set(F func, Set<>, Sets... others);
template <typename E, typename NextSet, typename... Sets, typename F>
void apply_item(F func, cons<E>, NextSet, Sets...);
template <typename E, typename F>
void apply_item(F func, cons<E> e);
Where combine is the outer (exposed) function, apply_set is used to iterate on the sets and apply_item is used to iterate on the types within a set.
The implementations are simple:
template <typename Head, typename... Tail, typename... Sets, typename F>
void apply_set(F func, Set<Head, Tail...>, Sets... others) {
apply_item(func, cons<Head>{}, others...);
apply_set(func, Set<Tail...>{}, others...);
} // apply_set
template <typename... Sets, typename F>
void apply_set(F, Set<>, Sets...) {}
template <typename E, typename NextSet, typename... Sets, typename F>
void apply_item(F func, cons<E>, NextSet ns, Sets... tail) {
Forwarder<F, E> forwarder(func);
apply_set(forwarder, ns, tail...);
}
template <typename E, typename F>
void apply_item(F func, cons<E> e) {
func(e);
} // apply_item
template <typename FirstSet, typename... Sets, typename F>
void combine(F func) {
apply_set(func, FirstSet{}, Sets{}...);
} // combine
For each of apply_set and apply_item we have a recursive case and a base case, though it's some kind of co-recursion here as apply_item calls back to apply_set.
And a simple example:
struct Dummy0 {}; struct Dummy1 {}; struct Dummy2 {};
struct Hello0 {}; struct Hello1 {};
struct Tested {
Tested(int i): value(i) {}
void operator()(cons<Dummy0>, cons<Hello0>) { std::cout << "Hello0 Dummy0!\n"; }
void operator()(cons<Dummy0>, cons<Hello1>) { std::cout << "Hello1 Dummy0!\n"; }
void operator()(cons<Dummy1>, cons<Hello0>) { std::cout << "Hello0 Dummy1!\n"; }
void operator()(cons<Dummy1>, cons<Hello1>) { std::cout << "Hello1 Dummy1!\n"; }
void operator()(cons<Dummy2>, cons<Hello0>) { std::cout << "Hello0 Dummy2!\n"; }
void operator()(cons<Dummy2>, cons<Hello1>) { std::cout << "Hello1 Dummy2!\n"; }
int value;
};
int main() {
Tested tested(42);
combine<Set<Dummy0, Dummy1, Dummy2>, Set<Hello0, Hello1>>(tested);
}
Which you can witness live on Coliru prints:
Hello0 Dummy0!
Hello1 Dummy0!
Hello0 Dummy1!
Hello1 Dummy1!
Hello0 Dummy2!
Hello1 Dummy2!
Enjoy :)
Note: it was presumed that the functor was cheap to copy, otherwise a reference can be used, both when passing and when storing it in Forwarder.
Edit: removed the cons around Set (everywhere it appeared), it's unnecessary.
Functions doesn't allow partial specializations, unless the specialization is complete. Every new different function signature declares a new overload, unless their signatures are exactly the same.
Try instead the following code:
#include <iostream>
template<typename Aux_type>
void test_helper()
{}
template<typename Aux_type, typename Head, typename... Tail>
void test_helper() {
std::cout << Head::i;
test_helper<Aux_type, Tail...>();
}
template<typename... Args>
void test()
{
test_helper<void, Args...>();
}
struct A{
static const int i=1;
};
struct B{
static const int i=2;
};
int main() {
test<A, B>();
return 0;
}
and it does compile (and prints 12).
Anyway, I've not understood your pseudocode sample.
I think that C++ is not the right tool, when it comes to convenient and flexible code generation ... Just write a simple utility in a scripting language of your choice, like in python:
generate_test_code.py:
#!/usr/bin/python
for HashFuction in {"Sha256", "Sha512", "Sa512_256", "Sha3_256", "Sha3_512"}:
for KeyingWrapper in {"TwoPassKeyedHash", "OnePassKeyedHash", "PlainHash"}:
for InstantiatedGetLeaf in {"GetLeaf<8>", "GetLeaf<1024>"}:
for Algorithm in {"algA", "algB", "algC"}:
print("runAndTime<{},{},{},{}>(someArgs);".format(HashFuction,KeyingWrapper,InstantiatedGetLeaf,Algorithm))
... then in your Makefile:
generated_test_code.cpp: generate_test_code.py
python generate_test_code.py > generated_test_code.cpp
... and in your c++ code, simply #include "generated_test_code.cpp" where you want it.

How to use variadic templates to make a generic Lua function wrapper?

For my current project, I've been writing a lot of C/C++ to Lua wrappers. A large number of these are simple setters and getters, so I managed to write some templates that make it easy to generate these, like so:
// Class Return Field
template <typename T, typename U, U T::*Member>
int luaU_get(lua_State* L)
{
T* obj = luaW_check<T>(L, 1);
luaU_push<U>(L, obj->*Member);
return 1;
}
static luaL_reg Foo_Table[] =
{
...
// Now I can just use this generic template to avoid
// writing simple getter functions
{ "getbar", luaU_get<Foo, Bar, &Foo::bar> },
...
};
I would like to do something similar for simple function wrappers for arbitrary functions too. For example, it would be nice to be able to do this:
template <typename T, typename U, U (T::*Func)(), typename... Args>
int luaU_func(lua_State* L)
{
// ...?
}
static luaL_reg Foo_Table[] =
{
...
{ "baz", luaU_func<Foo, int, &Foo::baz, int, float> },
...
};
The idea is that the template effectively turn out to be this when compiled:
int luaU_func(lua_State* L)
{
luaU_push<int>(L, luaW_check<Foo>(L, 1)->baz(luaU_check<int>(L, 2), luaU_check<float>(L, 3)));
return 1;
}
I've tried just using the ... expander, the problem for me is the integer index values to map to the proper arguments. I can't think of a way to get them working right. Is such a thing even possible?
(there is a little bit of magic going on here already; I wrote some templated wrappers for things like lua_push and lua_check. All of those existing wrappers can be found here)
The trick is to exploit template argument deduction by partially specializing a class template that contains the wrapper function:
// Lua API dummies ...
struct lua_State {};
template<class T> void luaU_push(lua_State*,T);
template<class T> T* luaW_check(lua_State*,int);
template<class T> T luaU_check(lua_State*,int);
// metaprogramming for creating indices ...
template<int...Ints>
struct int_pack {};
template<int Begin, int Count, int...Tail>
struct make_int_range_type {
typedef typename make_int_range_type<Begin,Count-1,Begin+Count-1,Tail...>::type type;
};
template<int Begin, int...Tail>
struct make_int_range_type<Begin,0,Tail...> {
typedef int_pack<Tail...> type;
};
template<int Begin, int Count>
inline typename make_int_range_type<Begin,Count>::type
make_int_range()
{ return typename make_int_range_type<Begin,Count>::type(); }
// the actual wrapper ...
template<class MemFunPtrType, MemFunPtrType PMF>
struct lua_mem_func_wrapper;
template<class Clazz, class ReturnType, class...Args, ReturnType(Clazz::*PMF)(Args...)>
struct lua_mem_func_wrapper<ReturnType(Clazz::*)(Args...),PMF> {
static int doit(lua_State* L) {
return doit_impl(L,make_int_range<2,sizeof...(Args)>());
}
private:
template<int...Indices>
static int doit_impl(lua_State* L, int_pack<Indices...>) {
luaU_push<ReturnType>(L,
(luaW_check<Clazz>(L, 1)->*PMF)(
luaU_check<Args>(L, Indices)...
)
);
return 1;
}
};
#define GET_MEM_FUN_WRAPPER(...) &lua_mem_func_wrapper<decltype(__VA_ARGS__),__VA_ARGS__>::doit
// testing ...
struct foo {
int baz(int, float);
};
void test() {
auto* ptr = GET_MEM_FUN_WRAPPER(&foo::baz);
}
This code compiles under G++ 4.6.1 using the options -c --std=c++0x. To see whether it really does what you want, please test it ...
Reusing the indices generation code from this answer and ignoring the function call to Func (don't know how exactly this is intended to be used), this is how it could look like:
template <typename T, typename U, U (T::*Func)(),
typename... Args, size_t... Idx>
int luaU_func_impl(lua_State* L, Collection<Idx...>)
{
luaU_push<int>(L, luaW_check<U>(L, 1), luaU_check<Args>(L, Idx+2)...);
return 1;
}
template <typename T, typename U, U (T::*Func)(), typename... Args>
int luaU_func(lua_State* L)
{
typename GenerateCollection<Args...>::type Indices;
return luaU_func_impl<T, U, Func, Args...>(L, Indices);
}