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

Storing multiple types into the same container

本文关键字:同一个 存储 类型      更新时间:2023-10-16

简介

假设我有以下内容

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

我想做的是将传递给value的任何值存储到std::vector或其他东西中,而不将其转换为模板类(因为这无论如何都不能解决我的问题(

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

尝试的想法

空指针

我最初的方法是使用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>

其他事情

看过的所有其他示例都做了我正在做的事情,但希望您以一种或另一种方式跟踪对象的类型,或使用 boost。

博士

我可以尝试做什么,以便我可以传递一个 int 类型的参数并存储到std::list等中,同时使用相同的模板函数传递类型为"cheese"的参数(一个假想类,专用于用奶酪填充您的程序(并将其存储到同一个列表中,等等

我不知道这是否会解决你的问题,但是你可以为容器使用一些多态类型,并将对象封装在泛型派生类中,所以从派生类的成员函数调用对象的成员函数可以有完整的类型信息(它们将是专门的模板(,但你的"东西"不会是泛型的, 客户端代码不会关心(甚至不知道(这种固有性:

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();
    }
};

Yo 可以通过以下方式进行测试:

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;
}

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

我认为我提出的是一个奇怪的实现"类型擦除"(你应该谷歌这个术语以找到更详细的解决方案(。