【问题标题】:Storing multiple types into the same container [duplicate]将多种类型存储到同一个容器中[重复]
【发布时间】:2014-12-11 18:51:24
【问题描述】:

简介

说我有关注

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&lt;AClass&gt; 的列表中,当它的类型为std::list&lt;BClass&gt;std::list&lt;int&gt; 等时

其他事情

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

tl;博士

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

【问题讨论】:

  • 你不能有一个异构的std::list。充其量,你可以有一个std::list&lt;A&gt;,其中元素实际上是派生类BCD,它们都派生自A。如果你愿意,有boost classes提供异构容器跨度>
  • @Cyber​​ 你能用一个例子发布你所说的作为答案吗?这个想法是我不使用 boost
  • 为避免重复,请参阅我上面发布的链接,了解如何使用boost 来完成此操作的示例。
  • @Cyber​​ 需要是 std::list&lt;A*&gt;(或类似名称)。
  • 您尝试做的事情非常困难,因此使用boost::variant 是一个好主意。它在那里,它被调试,它工作。在这一点上,您是否会正确执行此操作是值得怀疑的。当你设法做到这一点时,无论如何你都会得到类似boost::variant 的东西,除非你需要做很多工作才能到达那里。恕我直言,这不值得。

标签: c++


【解决方案1】:

我不知道这是否能解决你的问题,但是你可以为容器使用一些多态类型,并将对象封装在一个泛型派生类中,这样从派生类的成员函数中调用对象的成员函数就可以了具有完整的类型信息(它们将是专门的模板),但您的“事物”不会是通用的,并且客户端代码不会关心(甚至不知道)这个继承:

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

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

我认为我提出的是一种奇怪的实现“类型擦除”(您应该在谷歌上搜索这个术语以找到更详细的解决方案)。

【讨论】:

    猜你喜欢
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2017-05-30
    • 2016-03-12
    相关资源
    最近更新 更多