Вектор указателей на экземпляры шаблонного класса - PullRequest
2 голосов
/ 01 марта 2012

Я внедряю систему времени выполнения задач, которая поддерживает буферы для пользовательских объектов различных типов.Кроме того, все объекты перед переносом сохраняются в буферах.Поскольку среда выполнения не знает типы объектов, которые будет предоставлять пользователь, классы Wrapper и Buffer являются шаблонными:

template <typename T>
class Wrapper {
private:
    T mdata;
public:
    Wrapper() = default;
    Wrapper(T& user_data) : mdata(user_data) {}
    T& GetData() { return mdata; }
    ...
};

template <typename T> 
class Buffer {
private:
    std::deque<Wrapper<T>> items;
public:
    void Write(Wrapper<T> wd) {
        items.push_back(wd);
    }

    Wrapper<T> Read() {
        Wrapper<T> tmp = items.front();
        items.pop_front();
        return tmp;
    }
    ...
};

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

Вот где моя проблема: 1) каждая задача должна сохранять ссылки на несколько буферов (это число неизвестно во время компиляции) 2) буферы разных типов (в зависимости от хранимого класса Buffer).3) задача должна использовать эти ссылки для доступа к буферам.

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

Поэтому я думал сохранить ссылки как пустые указатели, где класс Task будет выглядеть примерно так:

class Task {
private:
    vector<void *> buffers;
public:
    template<typename T>
    void AddBuffer(Buffet<T>* bptr) {
        buffers.push_back((void *) bptr);
    }

    template<typename T>
    Buffer<T>* GetBufferPtr(int index) {
        return some_way_of_cast(buffers[index]);
    }
    ...
};

Проблема в том, что я не знаю, как получитьдействительный указатель из пустого указателя для доступа к буферу.А именно, я не знаю, как сохранить тип объекта, на который указывают buffers [index] .

Можете ли вы помочь мне с этим или предложить какое-то другое решение?

РЕДАКТИРОВАТЬ: буферы являются только детали реализации системы времени выполнения, и пользователь не знает об их существовании.

Ответы [ 3 ]

1 голос
/ 01 марта 2012

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

    class Task {
    private:
        vector<void *> buffers;
    public:
        void AddBuffer(char* bptr) {
            buffers.push_back((void *) bptr);
        }

        char *GetBufferPtr(int index) {
            return some_way_of_cast(buffers[index]);
        }
        ...
    };

  class RTTask: public Task {
  /* ... */
  void do_stuff() {
     Buffer<UserType1> b1; b1Id = b1.id();
     Buffer<UserType2> b2; b2Id = b2.id();

     AddBuffer(cast(&b1));
     AddBuffer(cast(&b2));
  }
  void do_stuff2() {
    Buffer<UserType1> *b1 = cast(GetBufferPtr(b1Id));
    b1->push(new UserType1());
  }
};

В этих случаях приведение в коде пользователя. Но, возможно, у вас другая проблема. Также класс Wrapper может не понадобиться, если вы можете переключаться на указатели.

0 голосов
/ 01 марта 2012

Это не совсем ответ на ваш вопрос, но я просто хотел указать на то, как вы написали

Wrapper<T> Read() { 

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

По той же причине функция-член STL stack::pop() возвращает void, а не объект, извлеченный из стека.

0 голосов
/ 01 марта 2012

Что вам нужно, это то, что называется стирание типа. Это способ скрыть тип (ы) в шаблоне.

Основная техника заключается в следующем: - Иметь абстрактный класс с нужным вам поведением, объявленным в независимой от типа манере. - Извлекайте свой шаблонный класс из этого класса, реализуйте его виртуальные методы.

Хорошие новости, вам, вероятно, не нужно писать свои собственные, там уже boost::any. Поскольку все, что вам нужно, это получить указатель и вернуть объект, этого должно быть достаточно.

Работа с void* - плохая идея. Как уже упоминалось, код, работающий с буферами, не должен заботиться о типе. Хорошо бы поработать с char*. Этот тип обычно используется для буферов (например, сокет apis). Это безопаснее, чем слишком: в стандарте есть специальное правило, которое позволяет более безопасное преобразование в char* (см. Правила наложения имен).

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