1

I am bound to some APIs and I am tied to some function signatures like here:

static bool WrapperFunction(JSContext *cx, unsigned argc, JS::Value *vp)

I try to wrap objects and functions to use in javascript under SpiderMonkey.

To integrate some C API, must be implemented wrappers for object data and wrapper methods for some object.

My solution lead me to the following logic of the wrapper, in order to be able to call methods with several arguments, but I don't know how to achieve it:

    template<typename jsType, typename jsReturnType, typename MethodType, MethodType Method, typename... jsParamType>
static bool VAMethodRet(JSContext *cx, unsigned argc, JS::Value *vp)
{
    JS::CallArgs args = CallArgsFromVp(argc, vp);

    jsReturnType::PrivateType result = jsReturnType::PrivateTypeDefaultValue();

Here my issues begin:

  1. Expand ...jsParamType... pack with calling a method for each jsParamType in order to create a wrapper class object instance for matching the corresponding argument out of args to prepare calling the C API function.

    In other words, jsParamType tells the type it wraps so it can extract the C type object for each parameter to be passed to the C API function.

    The first jsParamType corresponds to the args[0], the second jsParamType to the args[1], etc. to the last jsParamType, which corresponds the args[argc].

    It is possible to get less elements in args than sizeof...jsParamType, in this case the base C object should be initialized with a default value.

    The meta-information of parameters or object wrappers is achieved with static methods already (jsParamType::jsType::PrivateTypeDefaultValue() for example).

    Eventually, the expanded pack should be an array or vector of heterogeneous objects.

    The matching function should be templated, based on jsParamType, but also get the index of the expanded variadic pack and the args local variable in order to get the correct object to parse - here is my first issue:

    How to pass the index to the method?

    I've tried to be inspired from here, but I can't make it work.

2.. After this, I plan to have a similar technique to here in order to call the C API function with the right arguments - is this possible?

  1. In the end, based on a static function of jsParamType, called IsOut(), the out values will update the content of args local variable, but this should be done again using a new expansion, similar to the first step, to put back some values using type info present in jsParamType elements.

The last thing to do would be to set the return value, which is trivial.

double-beep
  • 5,031
  • 17
  • 33
  • 41
mike
  • 408
  • 5
  • 18
  • "Expand ...jsParamType... pack with calling a method for each jsParamType in order to create a wrapper class object instance for matching the corresponding argument out of args to prepare calling the C API function." I'm not sure I follow. Can you post some pseudocode of what you wish this would look like, and what the result would be if the templates were expanded? – AndyG Apr 06 '16 at 21:18
  • Thank you. I have added some pseudo-code, ask if you need more clarification. – mike Apr 07 '16 at 06:11
  • The main problem I see is that, when you want to pass a parameter pack, that parameter pack also must appear as an argument to the function. In your scenario, the parameter pack does not appear in the function argument list, and therefore the compiler will ignore the pack. – AndyG Apr 07 '16 at 14:03
  • Indeed, there is no parameters pack, just template types pack to match against a "regular" collection, but I am sure it works to expand the variadic types pack only. I've tried this and it works without having parameters pack in the function signature itself. I just need to find a way to expand using a function instead of this `bool isOut[numArgs] = { jsParamType::IsOut()... };`, this function matching the index too in a for each per index, probably. – mike Apr 07 '16 at 15:08
  • I've forgot to say that `numArgs` is as follows: `const unsigned numArgs = sizeof...(jsParamType);` – mike Apr 07 '16 at 15:26
  • Yes, it works so long as the template arguments are explicit. Your problem is interesting. I will read closer and attempt to write up an answer, but you can get started by looking into `std::tuple` for your heterogeneous container, and `type_traits` for turning types into indexes. – AndyG Apr 07 '16 at 15:27
  • I try to use std::tuple, but I fail passing a tuple to some function when I try to expand the arguments of the tuple. See here, compiled from other articles: http://ideone.com/NP1tuo – mike Apr 12 '16 at 05:53
  • Are you trying to do something like [this](http://coliru.stacked-crooked.com/a/4bd594c2fd2dfa3b)? – AndyG Apr 12 '16 at 12:48
  • Actually not. I don't see the use in my case. I need more. That is just a test. The goal is to instantiate a new pack of variables based on the input arguments and specific types to unwrap them. That's why it seems to copy some variables from a vector to another collection. I need to call a function for each of the input arguments, which are wrappers, to extract their data, pass them to an C API function and wrap the result back (in order to return their values to the originating javascript). – mike Apr 12 '16 at 13:31
  • I have a pack of argument types (wrappers of C types) to be matched against an array of elements of these types: `template ` <-> `vp[n]`, where `sizeof...(Args) >= n`, to loop them knowing that v[0] is of type Args[0] ... v[n-1] is of type Args[n-1] (well, throwing an exception if not, but this is out of the scope here). In other words, I need to declare `Args[Is] t()` inside of a function, then `t <- v[Is].data` .So, if successfully extracts the vp wrappers' data and to create another pack of arguments for the C API function to be called like (pseudo-sort-of) `cf(args...)`. – mike Apr 12 '16 at 13:42
  • Considering [this](http://coliru.stacked-crooked.com/a/4bd594c2fd2dfa3b), my issue is that I need to pass the tuple to some function or from function to function. – mike Apr 12 '16 at 13:44
  • In my example, I guess the initialization is wrong. – mike Apr 12 '16 at 14:04
  • [This](http://coliru.stacked-crooked.com/a/f81c1bedcf84d19f) then? – AndyG Apr 12 '16 at 15:35
  • Thanks, I've managed this using vector too. I've tried to achieve the same by std::tuple, as you've advised me. I think it is difficult to use std::tuple, or I don't understand it yet... – mike Apr 12 '16 at 15:51
  • BTW, look here: http://ideone.com/Rihfre. – mike Apr 12 '16 at 15:58
  • `vector` to `vector` is fine; it sounds like what you're really looking for. If you want it to work with `std::tuple` for academic reasons, [it's not much different](http://coliru.stacked-crooked.com/a/4ef7a8a49ed0162a) – AndyG Apr 12 '16 at 17:11
  • Wow, thanks, I have done it by passing all the tuples until the copy of the members, but is this memory leaking? I see `new`, but where is the `delete`? – mike Apr 12 '16 at 19:58
  • I didn't do any `delete`... left as an exercise to the reader ;-) – AndyG Apr 12 '16 at 20:22
  • How do you expand a pack of contained types? If I have an inner type TT of T, how could I write in a function having a pack `typename...T`, a declaration of tuple of types contained in `T...`, like tuple? – mike Apr 12 '16 at 20:29
  • I see, it needs `typename` in front, i.e. `tuple` – mike Apr 12 '16 at 20:36
  • Did the code I posted solve the problem? I think I was approaching an understanding of what you wanted: Given a array of `void*` and knowledge of the array size and the underlying types, transform the `void*` into another array of the underlying types, with those values copy-constructed from the `void*` ones. For each value in this second array, call some overloaded or templated function. Is that correct? It's still admittedly difficult to understand what your post is asking. – AndyG Apr 13 '16 at 14:17
  • First of all, you are the only that helped me with this issue. So I owe you a big deal of thanks. You are close. I have some wrapped params to pass to a function and wrap the results back. It doesn't matter the solution chosen between vector or tuple. I have chosen tuple as I don't like to use void* and tuple allows me to modify its elements as long as I created it with defaults passed to make_tuple. So far I get this transform of wrapped params to native C ones. Next, I need to pass them at once to a C function. – mike Apr 13 '16 at 15:30
  • As in, transform the elements of the tuple into a parameter list for the C function? Take a peek at my [first example](http://coliru.stacked-crooked.com/a/4bd594c2fd2dfa3b) to see an example of doing something like that. The gist of it is `myfunction(std::get(myTuple)...)` where `Is` is from an `index_sequence` – AndyG Apr 13 '16 at 15:45
  • Welll, works except for cases when mixed types of passing is present: `bool f(int i, O* o)`, because the tuple to be used is because it is created from wrappers not aware how the members will be used, here a call would look like `f(i, &o)`. I don't figure out how to do that. – mike Apr 13 '16 at 20:23
  • You're not making this very easy for me :-). How about [something like this](http://coliru.stacked-crooked.com/a/d4a028f242faca37)? It's pretty limited as written, and not the most efficient if you have anything other than primitive types or small easily copyable objects. We could probably iterate on it to make something better, but the gist is that we attempt to convert each type in the tuple to the next argument in the function's argument list. – AndyG Apr 13 '16 at 22:23
  • Actually C++ does the things difficult or we are not doing the right way. – mike Apr 14 '16 at 05:24
  • I feel I am here: http://thbecker.net/articles/rvalue_references/section_07.html – mike Apr 14 '16 at 06:23
  • Can you show me an example where it didn't work? Also, perfect forwarding is about preserving reference qualifiers on a type, not converting the type to a desired one. – AndyG Apr 14 '16 at 10:34
  • Not yet, but I have opaque object instances provided by the C API in question. – mike Apr 14 '16 at 10:48
  • I did not try **yet** your solution. I have tried perfect forwarding as only `&&` replaced `&` for tuples in functions calls and std::forward was used in two places. (I'm lazy and a bit tired of weeks of trial and error, long compile times etc., but I will try your solution just to see how it performs on real cases) So far, using perfect forwarding works excepting enums, it _seems_ it can't convert, it says, the tuple argument of type enum. Any ideas? – mike Apr 14 '16 at 13:40
  • Perfect forwarding will not convert types into pointers to types. The types need to already be in pointer form. For your enum case, I think it would help me if you showed a code example, preferably via modifying my existing one. – AndyG Apr 14 '16 at 15:39
  • By the way, I updated the code example. [Here it is](http://coliru.stacked-crooked.com/a/4e2436e6bf171283) – AndyG Apr 14 '16 at 17:28
  • Super!, I'll test it now, but I need time to integrate it. I'll come back when I get results, thank you! – mike Apr 14 '16 at 19:12
  • What about this: `template void call_func_helper(Ret(*f)(ARGS...), std::tuple& tup, std::index_sequence) { f( convert_type(std::get(tup)) ...); }` ? – mike Apr 14 '16 at 20:31
  • That, my friend, would take me to actually post a full answer to explain :-)Does it work? If so, I think I understand what all you needed, and can answer the question. – AndyG Apr 14 '16 at 20:33
  • I think it is something related to my compiler, VC++ 2015. It compiles under it. Not under Ideone.com. Which one is right?? – mike Apr 14 '16 at 20:38
  • Remove `typename` from `convert_type void call_func_helper(Ret(*f)(ARGS...), std::tuple& tup, std::index_sequence) { f( convert_type(std::get(tup)) ...); }` is right. MSVC++ 2015 has seems to accept `typename` when it shouldn't... – mike Apr 14 '16 at 20:43
  • My example compiles in both clang and gcc under the `-std=c++14` options. Either you are using VC++2015 but compiling under 2013, or there is probably a bug with Microsoft. – AndyG Apr 14 '16 at 20:44
  • Anyway, the issue here is that I need to extract the method parameters somehow, otherwise it is difficult to write all the stuff, meaning I pass the method type and the method reference using template parameters. Note, all the templates in my case have several type parameters that need to be passed, but not always possible to be deduced. – mike Apr 14 '16 at 20:56
  • I have adapted your code a bit more to be closer of what I need, here: http://ideone.com/nxUiku. – mike Apr 15 '16 at 14:27
  • As comment, one more conversion function must be taken into account (at least), for passed by reference function parameters. – mike Apr 15 '16 at 20:17
  • potentially. Do you think you could update your OP with some even clearer description of what you need, taking into account what you've learned? Right now it's still a little unapproachable. – AndyG Apr 15 '16 at 20:36
  • Actually, I could post some code, although is basically yours. – mike Apr 16 '16 at 18:37
  • I have just one issue left, how to call functions depending on their scope. Taking as reference, for simplification, some method without parameters, it is differently called depending on being a static or instance method, or a pointer to a method in a structure or simply in the global space, like `(*M)();`, or `(obj->*M)()`. I need some specialization to cover them, including const methods. – mike Apr 16 '16 at 19:11
  • Admittedly you question is still difficult to follow on account of it being so big. I think a [mcve] will help us here. What I mean is: provide some stubbed objects representing each type you need, as well as the functions you need to call, and we can take it from there. – AndyG Apr 18 '16 at 16:26
  • The complexity of the code and the fact I have stubs to these functions only (Adobe Illustrator C API) makes the job very hard. If we start from [http://coliru.stacked-crooked.com/a/4e2436e6bf171283](here), how could be built a template to call functions that return a value (`R f(...)`) and functions that don't (`void f(...)`)? – mike Apr 19 '16 at 07:41
  • Should I write another specialized function traits for `void`? This would just double them, isn't it? – mike Apr 19 '16 at 07:47
  • If I understand correctly what you're asking for, then it shouldn't be too difficult. [See here](http://coliru.stacked-crooked.com/a/3f4082940c1b23ac) – AndyG Apr 19 '16 at 11:36
  • Yes, except for one thing. I have to return the value using a parameter of call_func, not its return value. How is that possible, knowing that I should pass a supplemental template parameter for the type of the return value and to pass there some type or void (if that's possible) and a return value in function's parameter? I am bound to SpiderMonkey's need to evaluate the success of an operation and I know I could do it by returning a value and bool as parameter, but I'm curious if it is possible .. this twisted way :)... too. – mike Apr 19 '16 at 11:51
  • One of the parameters should be returned? How do you wish to specify which one? – AndyG Apr 19 '16 at 14:26
  • I think you already specified it as I need in your example, http://coliru.stacked-crooked.com/a/4e2436e6bf171283, but it is not used `template. It should be a ref parameter when needed. void call_func_helper(Ret(*f)(ARGFirst, ARGS...), std::tuple& tup, std::index_sequence)`, as Ret. Here too: http://coliru.stacked-crooked.com/a/3f4082940c1b23ac. – mike Apr 19 '16 at 15:11
  • "it should be a ref parameter", what is "it" here? Please be precise. – AndyG Apr 19 '16 at 19:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109595/discussion-between-andyg-and-mike). – AndyG Apr 19 '16 at 20:26

1 Answers1

1

Thanks to the help and patience of AndyG, I have achieved my goal. Here is a sample of code with the note that actual wrappers are not provided, as they are specific from case to case. So, they are simulated by simply passing parameters.

#include <iostream>
#include <functional>
#include <tuple>
#include <type_traits>
#include <vector>
using namespace std;

#include <functional>
#include <tuple>
#include <type_traits>
using namespace std;

template<typename T, typename U, std::enable_if_t<std::is_same<T, U>::value, int> = 0>
T convert_type(U _in)
{
    //return const_cast<U>(_in);
    return _in;
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_const_t<U>>::value, int> = 0>
T convert_type(U _in)
{
    //return const_cast<U>(_in);
    return _in;
}


// these conversion functions only can convert type to pointer to type, else return reference to type, so they're a bit limited
// pointer to pointer, or
template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_const_t<U>>::value, int> = 0>
T& convert_type(U& _in)
{
    return _in;
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_lvalue_reference_t<U>>::value, int> = 0>
T& convert_type(U& _in)
{
    return _in;
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_lvalue_reference_t<std::add_const_t<U>>>::value, int> = 0>
T& convert_type(U& _in)
{
    return _in;
}


// for conversion to pointer
//T&* to T*
template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_pointer_t<U>>::value, int> = 0>
T convert_type(U& _in)
{
    return std::addressof(_in);
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_const_t<U>>::value, int> = 0>
T convert_type(U& _in)
{
    return std::addressof(_in);
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_pointer_t<std::add_const_t<U>>>::value, int> = 0>
T convert_type(U& _in)
{
    return std::addressof(_in);
}

template<typename T>
struct function_traits;

template<typename R, typename ...Args>
struct function_traits<std::function<R(Args...)>>
{
    static const size_t nargs = sizeof...(Args);

    typedef R result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
    };

    static const bool isGlobalOrStaticContainer = true;
    static const bool isClassContainer = false;
    static const bool isPointerContainer = false;
    static const bool isConstInClassContainer = false;
    static const bool returnsVoid = std::is_same<R, void>::value;
};

template<typename C, typename R, typename ...Args>
struct function_traits<std::function<R(*C::*)(Args...)>>
{
    static const size_t nargs = sizeof...(Args);

    typedef R result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
    };

    static const bool isGlobalOrStaticContainer = false;
    static const bool isClassContainer = false;
    static const bool isPointerContainer = true;
    static const bool isConstInClassContainer = false;
    static const bool returnsVoid = std::is_same<R, void>::value;
};

template<typename C, typename R, typename ...Args>
struct function_traits<std::function<R(C::*)(Args...)>>
{
    static const size_t nargs = sizeof...(Args);

    typedef R result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
    };

    static const bool isGlobalOrStaticContainer = false;
    static const bool isClassContainer = true;
    static const bool isPointerContainer = false;
    static const bool isConstInClassContainer = false;
    static const bool returnsVoid = std::is_same<R, void>::value;
};

template<typename C, typename R, typename ...Args>
struct function_traits<std::function<R(C::*)(Args...) const>>
{
    static const size_t nargs = sizeof...(Args);

    typedef R result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
    };

    static const bool isGlobalOrStaticContainer = false;
    static const bool isClassContainer = true;
    static const bool isPointerContainer = false;
    static const bool isConstInClassContainer = true;
    static const bool returnsVoid = std::is_same<R, void>::value;
};

template<typename ParamType> class Param
{
public:

    typedef ParamType Type;

    static const bool isOut = false;
};

template<typename ParamType> class ParamOut : public Param<ParamType>
{
public:

    static const bool isOut = true;
};

template<typename Type, typename ReturnType, typename MethodType, MethodType Method, typename ParamType, size_t paramIndex, typename... ParamTypes>
static bool UnwrapParameter(unsigned argc, std::vector<void*>& args, typename ParamType::Type &ppt)
{
    if (argc > paramIndex)
    {
        ppt = *((std::add_pointer_t<typename ParamType::Type>(args[paramIndex])));
    }

    return true;
}

template<typename Type, typename ReturnType, typename MethodType, MethodType Method, typename... ParamType, size_t... paramIndex>
static bool UnwrapParameters(unsigned argc, std::vector<void*>& args, std::tuple<typename ParamType::Type...>& params, std::index_sequence<paramIndex...>)
{
    bool r[] = { true, UnwrapParameter<Type, ReturnType, MethodType, Method, ParamType, paramIndex, ParamType...>(argc, args, std::get<paramIndex>(params))... };

    bool res = true;
    for (size_t i = 0; i < sizeof...(ParamType) + 1 && res == true; i++)
        res &= r[i];
    return res;
}

template<typename Type, typename ReturnType, typename MethodType, MethodType Method, typename... ParamType>
static bool UnwrapParameters(unsigned argc, std::vector<void*>& args, std::tuple<typename ParamType::Type...>& params)
{
    return UnwrapParameters<Type, ReturnType, MethodType, Method, ParamType...>(argc, args, params, std::make_index_sequence<sizeof...(ParamType)>{});
}


template<typename Type, typename ReturnType, typename MethodType, MethodType Method, typename ParamType, size_t paramIndex, typename... ParamTypes>
static bool WrapParameter(unsigned argc, std::vector<void*>& args, typename ParamType::Type &ppt)
{
    if (ParamType::isOut && (argc > paramIndex))
    {
        // Wrap them back - nothing to do here, in this example
    }

    return true;
}

template<typename Type, typename ReturnType, typename MethodType, MethodType Method, typename... ParamType, size_t... paramIndex>
static bool WrapParameters(unsigned argc, std::vector<void*>& args, std::tuple<typename ParamType::Type...>& params, std::index_sequence<paramIndex...>)
{
    bool r[] = { true, WrapParameter<Type, ReturnType, MethodType, Method, ParamType, paramIndex, ParamType...>(argc, args, std::get<paramIndex>(params))... };

    bool res = true;
    for (size_t i = 0; i < sizeof...(ParamType)+1 && res == true; i++)
        res &= r[i];
    return res;
}

template<typename Type, typename ReturnType, typename MethodType, MethodType Method, typename... ParamType>
static bool WrapParameters(unsigned argc, std::vector<void*>& args, std::tuple<typename ParamType::Type...>& params)
{
    return WrapParameters<Type, ReturnType, MethodType, Method, ParamType...>(argc, args, params, std::make_index_sequence<sizeof...(ParamType)>{});
}


template<typename Type, typename ReturnType, typename MethodType,
    typename std::enable_if<function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::isPointerContainer, MethodType>::type Method,
    typename... ParamType, size_t... paramIndex>
    static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple<typename ParamType::Type...>& params, std::index_sequence<paramIndex...>)
{
    if (!(obj && (obj->*Method)))
        success = false;

    return (obj->*Method)(convert_type<typename function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::template arg<paramIndex>::type, typename ParamType::Type>(std::get<paramIndex>(params))...);
}

template<typename Type, typename ReturnType, typename MethodType,
    typename std::enable_if<function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::isGlobalOrStaticContainer, MethodType>::type Method,
    typename... ParamType, size_t... paramIndex>
    static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple<typename ParamType::Type...>& params, std::index_sequence<paramIndex...>)
{
    if (!(*Method))
        success = false;

    return (*Method)(convert_type<typename function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::template arg<paramIndex>::type, typename ParamType::Type>(std::get<paramIndex>(params))...);
}

template<typename Type, typename ReturnType, typename MethodType,
    typename std::enable_if<function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::isClassContainer, MethodType>::type Method,
    typename... ParamType, size_t... paramIndex>
    static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple<typename ParamType::Type...>& params, std::index_sequence<paramIndex...>)
{
    if (!(obj && (Method)))
        success = false;

    return (obj->*Method)(convert_type<typename function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::template arg<paramIndex>::type, typename ParamType::Type>(std::get<paramIndex>(params))...);
}

template <typename Type, typename ReturnType, typename MethodType, MethodType Method, typename... ParamType>
static ReturnType CallMethodRet(bool& success, Type* obj, std::tuple<typename ParamType::Type...>& params)
{
    return CallMethodRet<Type, ReturnType, MethodType, Method, ParamType...>(success, obj, params, std::make_index_sequence<sizeof...(ParamType)>{});
}


template<typename Type, typename ReturnType, typename MethodType,
    typename std::enable_if<!function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::returnsVoid, MethodType>::type Method,
    typename... ParamType>
static bool ExecuteMethod(Type* obj, unsigned argc, std::vector<void*>& args, ReturnType& result)
{
    try
    {
        const unsigned numArgs = sizeof...(ParamType);

        std::tuple<typename ParamType::Type...> params = std::make_tuple(typename ParamType::Type()...);

        if (!UnwrapParameters<Type, ReturnType, MethodType, Method, ParamType...>(argc, args, params))
            return false;

        bool success = true;

        result = CallMethodRet<Type, ReturnType, MethodType, Method, ParamType...>(success, obj, params);

        if (!success)
           return false; // Throw method not found here

        if (!WrapParameters<Type, ReturnType, MethodType, Method, ParamType...>(argc, args, params))
            return false;
    }
    catch (...)
    {
        // whatever...
    }

    return true;
}

template<typename Type, typename ReturnType, typename MethodType,
    typename std::enable_if<function_traits<std::function<typename std::remove_pointer<MethodType>::type>>::returnsVoid, MethodType>::type Method,
    typename... ParamType>
    static bool ExecuteMethod(Type* obj, unsigned argc, std::vector<void*>& args)
{
    try
    {
        const unsigned numArgs = sizeof...(ParamType);

        std::tuple<typename ParamType::Type...> params = std::make_tuple(typename ParamType::Type()...);

        if (!UnwrapParameters<Type, ReturnType, MethodType, Method, ParamType...>(argc, args, params))
            return false;

        bool success = true;

        CallMethodRet<Type, ReturnType, MethodType, Method, ParamType...>(success, obj, params);

        if (!success)
            return false; // Throw method not found here

        if (!WrapParameters<Type, ReturnType, MethodType, Method, ParamType...>(argc, args, params))
            return false;
    }
    catch (...)
    {
        // whatever...
    }
    return true;
}

class O 
{
public:
    void func(int a, string b, bool& c, const char* d)
    {
        std::cout << "Successfully called func with in values " << a << "," << b << "," << c << " and " << d << std::endl;

        c = true;

        std::cout << "Successfully called func with out values " << a << "," << b << "," << c << " and " << d << std::endl;
    }

    int func_i(int a, string b, bool& c, const char* d)
    {
        std::cout << "Successfully called func with in values " << a << "," << b << "," << c << " and " << d << std::endl;

        c = false;

        std::cout << "Successfully called func with out values " << a << "," << b << "," << c << " and " << d << std::endl;

        return 1;
    }
};

int main() {

    int a = 1;
    string b = "string";
    bool c = false;
    const char* d = "char*";

    std::vector<void*> v {(void*)&a, (void*)&b, (void*)&c, (void*)&d};

    std::cout << std::endl;

    O o;

    std::cout << ExecuteMethod<O, void, void(O::*)(int, string, bool&, const char*), &O::func, Param<int>, Param<string>, ParamOut<bool>, Param<const char*>>(&o, v.size(), v);

    std::cout << std::endl << std::endl;

    int result = 0;
    std::cout << ExecuteMethod<O, int, int(O::*)(int, string, bool&, const char*), &O::func_i, Param<int>, Param<string>, ParamOut<bool>, Param<const char*>>(&o, v.size(), v, result) << std::endl;
    std::cout << result << std::endl;

    return 0;
}
Community
  • 1
  • 1
mike
  • 408
  • 5
  • 18