将多种类型存储到同一容器中

时间:2014-12-11 18:51:24

标签: c++

简介

说我有以下

class thing {
    template<typename T> void method(T value) {}
}

我想要做的是将value传递给std::vector的任何值存储到void*或其他什么类型而不将其转换为模板类(因为这不能解决我的问题)无论如何都有问题)

我希望能够在不使用提升的情况下做到这一点(尽管我喜欢提升,但我不会一直使用它)

尝试过的想法

无效指针

我最初使用的是union,但是我会失去对象的类型,最终会导致不安全。

联盟/结构

我的下一个想法是使用struct / union type_wrapper { int a; char f; /* etc, etc, etc */ } ,如下所示:

template<typename T> 
class type_wrapper {
    T getType() { return /* get value of type/pointer/object here */ }
    /*Stored in some manner */
}

但是我会遇到跟踪类型的问题,所以我确保它在使用时保持不变。

包装类

接下来我尝试的是一个类,它会在函数调用中返回类型:

std::list<AClass>

问题与单独使用类型是一回事,因为当类型为std::list<BClass>std::list<int>等时,它无法存储在名为int的列表中

其他事项

我所看到的所有其他示例都做了我正在做的事情,但期望您以某种方式跟踪对象的类型,或使用提升。

TL;博士

我可以尝试这样做,以便我可以传递类型std::list的参数并存储到{{1}}等,同时使用相同的模板函数传递类型'cheese'的参数(虚构的课程,致力于用奶酪填充您的程序)并将其存储在相同的列表等

1 个答案:

答案 0 :(得分:2)

我不知道这是否会解决您的问题,但您可以为容器使用某种多态类型,并将该对象封装在通用派生类中,因此调用对象的成员函数来自派生班&#39;成员函数可以有完整的类型信息(它们将是专门的模板),但你的&#34;事物&#34;不会是通用的,客户代码不会关心(或甚至知道)这种关注:

class Aux {
public:
    virtual void DoSomething() =0 ;
};

template<typename T>
class AuxTemp : public Aux {
    T *real_obj;
public:
    AuxTemp(const T &obj) : real_obj(new T(obj)) {} // create
    AuxTemp(const AuxTemp &other) : real_obj(new T(*other.real_obj)) { } // copy
    AuxTemp(AuxTemp &&other) : real_obj(other.real_obj) { other.real_obj=nullptr; } // move
    ~AuxTemp() { delete real_obj; } // destroy
    void DoSomething() override { 
        real_obj->DoSomething(); // here we call the method with full type information for real_obj
    }
};

class Thing {
    std::vector<Aux*> v;
public:
    template<typename T> void Add(const T &value) {
        v.push_back(new AuxTemp<T>(value));
    }
    void DoSomethingForAll() { 
        for(auto &x:v) x->DoSomething();
    }
};

哟可以用以下方式测试:

class A {
public:
    void DoSomething() { std::cout << "A"<< std::endl; }
};

class B {
public:
    void DoSomething() { std::cout << "B"<< std::endl; }
};

int main(int argc, char *argv[]) {
    Thing t;
    t.Add(A{});
    t.Add(B{});
    t.DoSomethingForAll();
    return 0;
}

对于推送到向量的每个新类型,添加成员函数创建一个新的派生和专用包装类,因此虚拟表可以处理对DoSomething的调用,以便使用正确且完全意识到的实现类型版本。

我认为我提议的是一个奇怪的实现&#34; type-erasure&#34; (你应该谷歌这个术语来找到更详细的解决方案)。

相关问题