How to restore function pointer type at runtime

In the code, I register one or more function pointers in the manager class.

In this class, I have a map that maps the types of function arguments to the specified function. It might look like this:std::map< std::vector<std::type_index> , void*>

template<typename Ret, typename... Args>
void Register(Ret(*function)(Args...)) {
    void* v = (void*)function;
    // recursively build type vector and add to the map
}

At run time, the code receives calls (from an external script) with an arbitrary number of arguments. These arguments can be read as primitive data types or as custom types that will be specified at compile time.


With every call from the script, I need to figure out which function to call, and then call. The first is easy and already solved (filling the vector type_indexin the loop), but I can’t come up with a solution for the latter.

My first approach was to use variational templates in recursion with an added template argument for each type of read, but this was not possible because the templates are created at compile time and an arbitrary number of arguments are read at runtime.

Without variation patterns, however, I see no way to achieve this. I counted boost::anyinstead void*, but I did not see how this solves the need to return to the original type. I also thought about using std::function, but it would be a template type, so it could not be stored in the map for functions with different arguments.


( , , LuaBinds . , ( , pre-++ 11), .)

+4
3

, vector ().

. , invoke.

, template<class... Args>. Augment invoke.

, :

typedef std::vector<run_time_stuff> run_time_args;
template<class... Args>
void invoke( void(*func)(Args...), run_time_args rta )

. , . , , , .

:

template<class...Args>
std::function<void(run_time_args)> make_invoker(void(*func)(Args...)){
  return [func](run_time_args rta){
    invoke(func, rta);
  };
}

void* std::function<void(run_time_args)> - invokers. , make_invoker , void*.

, , , , . , , !

invoke - . , .

, - double int. std::vector< boost::variant<double, int> > run_time_args.

, invoke, .

enum class invoke_result {
  everything_ok,
  error_parameter_count_mismatch,
  parameter_type_mismatch,
};
typedef boost::variant<int,double> c;
typedef std::vector<run_time_stuff> run_time_args;
template<class... Args>
invoke_result invoke( void(*func)(Args...), run_time_args rta );

- :

template<unsigned...Is>struct indexes{typedef indexes type;};
template<unsigned Max,unsigned...Is>struct make_indexes:make_indexes<Max-1, Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;

invoker:

namespace helpers{
  template<unsigned...Is, class... Args>
  invoke_result invoke( indexes<Is...>, void(*func)(Args...), run_time_args rta ) {
    typedef void* pvoid;
    if (rta.size() < sizeof...(Is))
      return invoke_result::error_parameter_count_mismatch;
    pvoid check_array[] = { ((void*)boost::get<Args>( rta[Is] ))... };
    for( pvoid p : check_array )
      if (!p)
        return invoke_result::error_parameter_type_mismatch;
    func( (*boost::get<Args>(rts[Is]))... );
  }
}

template<class... Args>
invoke_result invoke( void(*func)(Args...), run_time_args rta ) {
  return helpers::invoke( make_indexes_t< sizeof...(Args) >{}, func, rta );
}

, func args , run_time_args.

, , std::move std::vector. . , , , .

+3

, .

delegate.h

template <typename ReturnType, typename ...Args>
class BaseDelegate
{
public:
    BaseDelegate()
        : m_delegate(nullptr)
    {

    }

    virtual ReturnType Call(Args... args) = 0;
    BaseDelegate* m_delegate;
};

template <typename ReturnType = void, typename ...Args>
class Delegate : public BaseDelegate<ReturnType, Args...>
{
public:
    template <typename ClassType>
    class Callee : public BaseDelegate
    {
    public:
        typedef ReturnType (ClassType::*FncPtr)(Args...);
    public:
        Callee(ClassType* type, FncPtr function)
            : m_type(type)
            , m_function(function)
        {

        }

        ~Callee()
        {

        }

        ReturnType Call(Args... args)
        {
            return (m_type->*m_function)(args...);
        }

    protected:
        ClassType* m_type;
        FncPtr m_function;
    };

public:
    template<typename T>
    void RegisterCallback(T* type, ReturnType (T::*function)(Args...))
    {
        m_delegate = new Callee<T>(type, function);
    }

    ReturnType Call(Args... args)
    {
        return m_delegate->Call(args...);
    }
};

main.cpp

class Foo
{
public:
    int Method(int iVal)
    {
        return iVal * 2;
    }
};

int main(int argc, const char* args)
{
    Foo foo;
    typedef Delegate<int, int> MyDelegate;

    MyDelegate m_delegate;
    m_delegate.RegisterCallback(&foo, &Foo::Method);

    int retVal = m_delegate.Call(10);

    return 0;
}
+1

, , std::function std::bind.

:

  • You know the functions you want to call and their arguments
  • Functions can have any signature and any number of arguments
  • You want to use style erasure to be able to store these functions and arguments, and call them all at a later point in time.

Here is a working example:

#include <iostream>
#include <functional>
#include <list>

// list of all bound functions
std::list<std::function<void()>> funcs;

// add a function and its arguments to the list
template<typename Ret, typename... Args, typename... UArgs>
void Register(Ret(*Func)(Args...), UArgs... args)
{
    funcs.push_back(std::bind(Func, args...));
}

// call all the bound functions
void CallAll()
{
    for (auto& f : funcs)
        f();
}

////////////////////////////
// some example functions
////////////////////////////

void foo(int i, double d)
{
    std::cout << __func__ << "(" << i << ", " << d << ")" << std::endl;
}

void bar(int i, double d, char c, std::string s)
{
    std::cout << __func__ << "(" << i << ", " << d << ", " << c << ", " << s << ")" << std::endl;
}

int main()
{
    Register(&foo, 1, 2);
    Register(&bar, 7, 3.14, 'c', "Hello world");

    CallAll();
}
0
source

Source: https://habr.com/ru/post/1539353/


All Articles