очередь объектов разных классов - PullRequest
0 голосов
/ 21 марта 2019

Мне нужно создать очередь из объектов разных классов (эти классы не связаны).Я нашел решение следующим образом:

Создать базовый класс и использовать полиморфизм.Вот как я это реализовал,

class Task {
    public:
    virtual void operator()() {
        printf("should not be called\n");    
    } 
};

class TaskRPCB : public Task {
    private:
        int x;
        // other varibles
        std::function<void(int)> func;
    public:
        TaskRPCB(std::function<void(int)>&f , int x) {
            this->func = f;
            this->x = x;
        }
        void operator()() {
            printf("TaskRPCB function is executing...\n");
            func(x);
        }
};

class TaskECB : public Task {
    private:
        // other varibles
        std::function<void(void)> func;
    public:
        TaskECB(std::function<void(void)>&f) : func(f) {}
        void operator()() {
            printf("TaskECB function is executing...\n");
            func();
        }
};

void F1() { // dummy function for example
    cout <<"no x"<<endl;
}
void F2(int x) { // dummy function for example
    cout <<"x : "<<x<<endl;
}

int main() {

    queue<unique_ptr<Task>> Q;

    function<void()>    func1   = F1;
    function<void(int)> func2   = F2;

    TaskECB task1(func1);
    TaskRPCB task2(func2,4);


    Q.emplace(new TaskECB(func1));
    Q.emplace(new TaskRPCB(func2,4));

    (*Q.front())();
    Q.pop();

    (*Q.front())();
    Q.pop();

}

Проблема в том, что я не могу push объекты напрямую, как показано выше.Мне нужно создать объект унаследованного класса и передать его другой функции для выполнения действия push.Это потому, что (в моем случае) очередь является частью thread-safe queue и имеет отдельный метод Push().

template<typename T>
void threadSafeQueue<T>::Push(T newData) { /* TODO: size check before pushing */
    std::shared_ptr<T> data(std::make_shared<T>(std::move(newData)));
                                           /* construct the object before lock*/
    std::lock_guard<std::mutex> lk(mut);
    taskQueue.push(data);
    dataCond.notify_one();
}

Раньше у меня не было нескольких tasks для выполнения (или отправки) в очередь, поэтому объявление threadSafeQueue<TaskRPCB> workQ отлично сработало.

Создание base Task class, как описано выше, не работает из-за нарезки объектов

Можете ли вы предложить другие способы хранения объектов в очереди (чтобы я все еще мог использоватьблокировка защищена Push() метод)

Спасибо!

обновление: правильный способ использования варианта?

typedef std::variant<TaskECB, TaskRPCB> myType;

int main() {

    queue<unique_ptr<myType>> Q;

    function<void()>    func1   = F1;
    function<void(int)> func2   = F2;

    TaskECB task1(func1);
    TaskRPCB task2(func2,4);

    myType x = task1;

    Q.push(make_unique<myType>(x));
    x = task2;
    Q.push(make_unique<myType>(x));

    if((*Q.front()).index() == 0) {
        auto f1 = get<TaskECB>(*Q.front());
        f1();
        Q.pop();
    }
    if((*Q.front()).index() == 1) {
        auto f1 = get<TaskRPCB>(*Q.front());
        f1();
        Q.pop();
    }

}

update2:

using myVariantType = std::variant<TaskECB, TaskRPCB>;

struct VisitPackage {
    void operator()(TaskECB & task) { 
        task();
    }
    void operator()(TaskRPCB& task) {
        task();
    }
};

int main() {
    queue<myVariantType> Q;

    function<void()>    func1   = F1;
    function<void(int)> func2   = F2;

    TaskECB task1(func1);
    TaskRPCB task2(func2,4);

    Q.emplace(task1);
    Q.emplace(task2);

    std::visit(VisitPackage(), Q.front());
    Q.pop();
    std::visit(VisitPackage(), Q.front());
    Q.pop();
}
...