0

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}
};
Azelekia
  • 35
  • 1
  • 4

1 Answers1

1

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.

Community
  • 1
  • 1
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380