Сохранить и вызвать функцию-член с неизвестными аргументами - PullRequest
1 голос
/ 08 апреля 2019

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

Я нашел этот фрагмент кода, чтобы получить лямбду:

template <auto Fn, typename T, typename R = void, typename... Args>
auto get_cb_inner(T* obj, R (T::*)(Args...) const) {
    return [obj](Args... args) -> R {
        return (obj->*Fn)(std::forward<Args>(args)...);
    };
}
template <auto Fn, typename T>
auto get_cb(T* obj) {
    return get_cb_inner<Fn, T>(obj, Fn);
}

НоЯ не могу понять, как я буду хранить его, а затем иметь возможность вызывать его во время выполнения с правильными параметрами.

У меня есть такая структура:

struct Job {
    void execute(Data& data, const OtherData& otherData) const {
       // do job
    }
};

auto exe_fn = get_cb<&Job::execute>(new Job());

Что я хочуДля этого нужно сохранить эту функцию «execute» в лямбде, а затем сохранить ее в вектороподобном контейнере (с другими функциями, которые могут иметь другие аргументы), который можно повторять и вызывать.

РЕДАКТИРОВАТЬ:

Используя код @KamilCuk, я создал эту оболочку-структуру без утечек памяти / ошибок seg.

template <typename... Args>
using exec_fn = std::function<void(Args...)>;
template <typename Job>
using job_ptr = std::unique_ptr<Job>;

template <typename J, typename R = void, typename... Args>
struct JobExecuteCaller {
    exec_fn<Args...> exec_fn;
    job_ptr<J> job_ptr;
    JobExecuteCaller (J* job, R (S::*f)(Args...) const)
        : job_ptr{job_ptr<J>(job)} {
        exec_fn = [this, f](Args... args) -> R {
            (job_ptr.get()->*f)(std::forward<Args>(args)...);
        };
    }
    void operator()(Args... args) { exec_fn(args...); }
};

auto process = JobExecuteCaller(new Job(), &Job::execute);
JobExecuteCaller(/*args ... */)

Теперь мне просто нужно найти способ хранения различныхвиды JobExecuteCallers.

1 Ответ

1 голос
/ 08 апреля 2019

Ты имеешь в виду, что хочешь std::bind?

#include <utility>
#include <new>
#include <iostream>
#include <functional>

struct Job {
    void execute(int a, int b) {
       std::cout << a << " " << b << std::endl;
    }
};

int main() {
    auto exe_fn = std::bind(&Job::execute, new Job(), 
        std::placeholders::_1, std::placeholders::_2);
    exe_fn(1, 2);
}

Я исправил твой код. Вам необходимо передать не только тип указателя на член функции, но и адрес указателя на член функции. Таким образом, вы можете назвать это.

#include <utility>
#include <new>
#include <iostream>
#include <functional>

template <typename T, typename R = void, typename... Args>
auto get_cb(T* obj, R (T::*f)(Args...)) {
    return [obj, f](Args... args) -> R {
        return (obj->*f)(std::forward<Args>(args)...);
    };
}

struct Job {
    void execute(int a, int b) {
        std::cout << a << " " << b << std::endl;
    }
};

int main() {
    auto exe_fn = get_cb(new Job(), &Job::execute);
    exe_fn(1, 2);
}

Обратите внимание, что в обоих примерах утечка памяти у new Job().

...