Как вызвать generi c std :: function со списком параметров void *? - PullRequest
0 голосов
/ 18 июня 2020

У меня есть std :: map, где я храню несколько произвольных методов, которые хочу вызвать позже.

map<string, function<void(void)>> methods;

template<typename R, typename ...P>
void storeMethod(const string& name, const function<R(P...)>& method) {
    methods[name] = method;
}    

Во время вызова я получаю параметры для вызова метода в vector<void*>, где первый элемент - это указатель, в котором я буду хранить возвращаемое значение.
Как мне автоматически преобразовать эти параметры в соответствующие типы метода, который я хочу вызвать?
Следует ли мне хранить типы в некоторых способ, возможно?

void callMethod(const string& name, vector<void*> parameters) {
    auto method = methods[name];
    // How to call 'method' with all the parameters casted to the required types?
}

Например, если я первоначально позвонил storeMethod() с помощью function<int(string a, float b)>, мне нужен общий c способ вызвать его в callMethod(), например:

*((int*)parameters[0]) = method(*((string*)parameters[1]), *((float*)parameters[2]));

Ответы [ 2 ]

1 голос
/ 18 июня 2020

Вам нужно будет заключить method во что-то, что может запоминать типы параметров.

struct OpaqueFunction {
    virtual std::any call(const std::vector<std::any> &) = 0;
};

template <typename R, typename ... Args>
struct OpaqueFunctionImpl : OpaqueFunction {
    OpaqueFunctionImpl(std::function<R(Args...)> f) : f(std::move(f)) {}

    std::any call(const std::vector<std::any> & parameters) override {
        return call_impl(parameters, std::index_sequence_for<Args...>{});
    }
private:
    template <size_t... I>
    std::any call_impl(const std::vector<std::any> & parameters, std::index_sequence<I...>) {
        return f(std::any_cast<Args>(parameters.at(I))...);
    }
    std::function<R(Args...)> f;
};

class Methods {
    std::map<std::string, std::unique_ptr<OpaqueFunction>> methods;
public:
    template<typename R, typename ... Args>
    void storeMethod(std::string name, std::function<R(Args...)> method) {
        methods[std::move(name)] = std::make_unique<OpaqueFunctionImpl<R, Args...>>(std::move(method));
    }

    template<typename R>
    R callMethod(const std::string & name, const std::vector<std::any> & parameters) {
        return std::any_cast<R>(methods.at(name)->call(parameters));
    }
};
0 голосов
/ 18 июня 2020

Вы можете создать тип Callable для функций, которые принимают различные типы аргументов, а затем сохранить его в vector (используя здесь вектор для простоты):

struct Callable {
    Callable(std::function<void()> f) : zero_(std::move(f)) {}
    Callable(std::function<void(int)> f) : one_(std::move(f)) {}

    void operator()() { zero_(); }
    void operator()(int x) { one_(x); }

    std::function<void()> zero_;
    std::function<void(int)> one_;
};

//vector of methods
std::vector<Callable> methods;

Чтобы сохранить метод , вы можете использовать функцию в формате template или просто использовать перегрузки. Я использую здесь перегрузки:

void addMethod(std::function<void()> func)
{
    methods.push_back(Callable(func));
}

void addMethod(std::function<void(int)> func)
{
    methods.push_back(Callable(func));
}

А затем, чтобы наконец вызвать функцию:

template<typename ...Args>
void callMethod(int idx, Args ...args) {
    auto method = methods[idx];

    method(std::forward<Args>(args)...);
 }

Main:

int main()
{
    addMethod([](int x){
        std::cout << "I am function(int)" << x << '\n';
    });

    addMethod([](){
        std::cout << "I am just function()\n";
    });


    callMethod(0, 200);
    callMethod(1);
}

Это самый простой из возможных способов. можно придумать, чтобы добиться этого. Это могут быть способы получше, и мне действительно интересно.

Попробуйте здесь: https://godbolt.org/z/HS5a7p

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...