指向传染媒介对templated类的实例

时间:2012-02-29 22:27:50

标签: c++ templates void-pointers

我正在实现一个任务运行时系统,它为各种类型的用户提供的对象维护缓冲区。此外,所有对象在存储到缓冲区之前都会被包装。由于运行时不知道用户将提供的对象类型,因此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类创建一个基类,然后使用基类指针,因为Buffer类中的方法 Write Read 已被模板化,因此不可能是虚拟的。

所以我想把引用保留为void指针,其中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]);
    }
    ...
};

这个问题是我不知道如何从void指针获取有效指针以访问Buffer。也就是说,我不知道如何保留 buffers [index] 所指向的对象的类型。

你能帮我解决这个问题,还是建议其他解决方案?

编辑:缓冲区只是运行时系统的实现细节,用户不知道它们的存在。

3 个答案:

答案 0 :(得分:1)

根据我的经验,当用户类型保存在用户代码中时,运行时系统处理缓冲区不需要担心这些缓冲区的实际类型。用户可以在类型缓冲区上调用操作。

    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类也可能没有必要。

答案 1 :(得分:0)

你需要的是一种叫做类型擦除的东西。这是隐藏模板中类型的方法。

基本技术如下:   - 在一个独立于类型的maner中声明一个具有所需行为的抽象类。   - 从该类派生模板类,实现其虚拟方法。

好消息,你可能不需要自己写boost::any了。因为您需要的只是获取指针并将对象取回,这应该足够了。

现在,使用void*是一个坏主意。如上所述,处理缓冲区的代码不应该关心类型。好的方法是与char*合作。这是通常用于缓冲区的类型(例如socket apis)。它比更安全:标准中有一条特殊规则允许更安全地转换为char*(参见别名规则)。

答案 2 :(得分:0)

这不是你问题的答案,但我只是想指出你的写作方式

Wrapper<T> Read() { 

使它成为一个mutator成员函数,它按值返回,因此不是好习惯,因为它强制用户编写异常不安全代码。

出于同样的原因,STL stack::pop()成员函数返回void,而不是从堆栈弹出的对象。