Передача пользовательских функций в базовый абстрактный класс для отложенного выполнения - PullRequest
1 голос
/ 11 февраля 2020

Я хотел бы узнать, как создать абстракцию над классом Task, который может принимать объекты любой функции или функтора (вместе с его аргументами и т. Д. c) и сохранять его для последующего выполнения или распространять в некоторых потоках, независимо от того, .

Я немного поэкспериментировал с std::function и шаблонными классами, но не смог. Поэтому я хотел бы сначала скомпилировать его, а затем запустить, чтобы ознакомиться с концепциями, а затем я буду искать более эффективный шаблон для своих нужд. Итак, вопрос в том, как мне сначала скомпилировать код для первого шага? Код показан ниже.

#include <iostream>
#include <string>
#include <queue>
#include <memory>
#include <functional>

class ITask
{
    public:
    virtual ~ITask() = default;
    virtual void execute() = 0;
};

template<typename ReturnType, typename... Args>
class GameTask : ITask
{
    explicit GameTask(std::function<ReturnType(Args...)>& func) :
        func_(func)
    {}

    void execute()
    {
        // func(Args...); ??
    }

private:
    std::function<ReturnType(Args...)> func_;
};


// lets imitate some bigger classes with various methods
class BigClassA
{
public:
    void func1(int a) { std::cout << ++a; }
    int func2(const std::string& s) { std::cout << s; return b; }

    int b = 4;
};

class BigClassB
{
public:
    double func1(BigClassA& bca, int i) { bca.b += i; return 0.1; }
};

int main()
{
    BigClassA a;
    BigClassB b;

    // perform immidiately by current main thread:
    a.func1(2);
    b.func1(a, 3);
    a.func2("Hello");


    //store under queue for later execution
    std::queue<std::unique_ptr<ITask>> queue;

    /*  a.func1(2);  */
    // queue.push(std::make_unique<GameTask>( [&a](){ a.func1(2); } ));

    /*  b.func1(a, 3);  */
    //  queue.push(std::make_unique<GameTask>(  ));

    /*  a.func2("Hello");  */
    // queue.push(std::make_unique<GameTask>(  ));


    while (queue.size())
    {
        queue.front()->execute();
        queue.pop();
    }

}

edit:

Варади c действительно был иголками здесь. Вот код, который я сейчас получаю:

#include <iostream>
#include <string>
#include <queue>
#include <memory>
#include <functional>

class ITask
{
public:
    virtual ~ITask() = default;
    virtual void execute() = 0;
};

class GameTask : public ITask
{
public:
    GameTask(std::function<void()> func) : func_(func) {}

    void execute() final
    {
        func_();
    }

private:
    std::function<void()> func_;
};

// lets imitate some bigger classes with various methods
class BigClassA
{
public:
    void func1(int a) const { std::cout << ++a; }
    int func2(const std::string& s) { std::cout << s; return b; }

    int b = 4;
};

class BigClassB
{
public:
    double func1(BigClassA& bca, int i) { bca.b += i; return 0.1; }
};

int main()
{
    BigClassA a;
    BigClassB b;

    // perform immidiately by current main thread:
    a.func1(2);
    b.func1(a, 3);
    a.func2("Hello");

    //store under queue for later execution
    std::queue<std::unique_ptr<ITask>> queue;

    queue.push(std::make_unique<GameTask>( [&a]() { a.func1(2); } ));

    queue.push(std::make_unique<GameTask>( [&a, &b]() {b.func1(a, 3); } ));

    queue.push(std::make_unique<GameTask>( [&a]() { a.func2("Hello"); } ));


    // delayed execution
    while (queue.size())
    {
        queue.front()->execute();
        queue.pop();
    }

}

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

1 Ответ

1 голос
/ 11 февраля 2020

Вот рабочая версия кода с некоторыми изменениями. Хотя дизайн мог бы быть значительно улучшен, НО, я просто изменил ваш код для компиляции и работы.

#include <iostream>
#include <string>
#include <queue>
#include <memory>
#include <functional>
#include <queue>

template<typename ReturnType, typename... Args>
class ITask
{
public:
   virtual ~ITask() = default;
   virtual void execute(Args ...) = 0;
};

template<typename ReturnType, typename... Args>
class GameTask : public ITask<ReturnType, Args...>
{
public:
   GameTask(std::function<ReturnType(Args...)>& func) :
      func_(func)
   {
   }

   void execute(Args ... args) override
   {
      func_(args...); 
   }

private:
   std::function<ReturnType(Args...)> func_;
};


// lets imitate some bigger classes with various methods
class BigClassA
{
public:
   void func1(int a) { std::cout << ++a; }
   int func2(const std::string& s) { std::cout << s; return b; }

   int b = 4;
};

class BigClassB
{
public:
   double func1(BigClassA& bca, int i) { bca.b += i; return 0.1; }
};

int main()
{
   BigClassA a;
   BigClassB b;

   // perform immediately by current main thread:
   a.func1(2);
   b.func1(a, 3);
   a.func2("Hello");


   //store under queue for later execution
   std::queue<std::unique_ptr<ITask<void , int>>> queue;

   a.func1(2);
    queue.push(std::make_unique<GameTask<void, int>>(std::function<void(int)>([&a](int x) { a.func1(2); })));

   b.func1(a, 3);
   queue.push(std::make_unique<GameTask<void, int>>(std::function<void(int)>([&b , &a](int x) { b.func1(a , 122); })));

   a.func2("Hello");  
   queue.push(std::make_unique<GameTask<void, int>>(std::function<void(int)>([&a](int x) { a.func2("Hi"); })));


   while (queue.size())
   {
      queue.front()->execute(3);
      queue.pop();
   }
}

Редактировать 1: Обновлен элемент std::queue для работы с типом polymorphi c.

...