C++如何创建异构容器

Posted

技术标签:

【中文标题】C++如何创建异构容器【英文标题】:C++ How to create a heterogeneous container 【发布时间】:2010-07-09 11:15:05 【问题描述】:

我需要以 (name, value) 的形式存储一系列数据点,其中的值可以采用不同的类型。

我正在尝试为每个数据点使用一个类模板。然后对于我看到的每个数据点,我想创建一个新对象并将其推回向量中。对于每种新类型,我需要先从模板创建一个新类。但是我不能存储在任何向量中创建的对象,因为向量期望所有条目的类型相同。我需要存储的类型不能适合继承层次结构。他们是无关的。将来还会创建更多类型,我不想为每种新类型更改存储服务。有没有办法创建一个异构容器来存储这些条目? 谢谢!

【问题讨论】:

它展示了一种处理运行时多态性的方法。我想这是相关的。 youtu.be/vxv74Mjt9_0?t=16m8s How can I store objects of differing types in a C++ container?的可能重复 【参考方案1】:

C++17 及更高版本。

std::any 允许保存任何类型,但需要知道存储的类型才能检索它。

但是,如果您有一组已知类型,您可能更喜欢std::variant

using variant_type = std::variant<Foo, Bar, Joe>;

int func(variant_type const& v) // not template

    auto const visitor = [](auto const& t)
    
        if constexpr (std::is_same_v<Foo const&, decltype(t)>)
        
            return t.fooish();
        
        else
        
            return t.barjoeish();
        
    ;

    return std::visit(visitor, v);

快速定义访问者的有用技巧:

template <typename... Ts> struct overload : Ts...

    overload(Ts... aFns) : Ts(aFns)... 
    using Ts::operator()...;
;
template <typename... Ts> overload(Ts...) -> overload<Ts...>;

//  Used as
auto const visitor = overload(
    [](Foo const& foo)  return foo.fooish(); ,
    [](auto const& other)  return other.joebarish(); 
);

return std::visit(visitor, variant);

C++17 之前的版本。

boost::any 已被推荐,但它适用于任何用途,因此您不能期望太多。

如果你提前知道各种类型,最好使用boost::variant

typedef boost::variant<Foo, Bar, Joe> variant_type;

struct Print: boost::static_visitor<>

  void operator()(Foo const& f) const  f.print(std::cout); 

  template <class T>
  void operator()(T const& t) const  std::cout << t << '\n'; 
;

void func(variant_type const& v) // not template

  boost::apply_visitor(Print(), v); // compile-time checking
                                    // that all types are handled

【讨论】:

没错!值得注意的是,从 C++17 开始,这些都是标准库的一部分。 @Vorac:好点,答案已更新和扩展。【参考方案2】:

boost 库可能有您正在寻找的东西(boost::any)。如果您不能使用 boost,您可以使用包装指针方法自行滚动...

【讨论】:

谢谢!我认为“任何”都会起作用!我还找到了一个基于 boost::any 的教程。在这里,如果有人需要这个! devx.com/cplus/10MinuteSolution/29757/1954【参考方案3】:

像这样的容器的问题在于,当您想访问容器中的某些内容时,您必须确定其类型,然后以某种方式将其转换为实际类型。这是丑陋、低效且容易出错的,这就是为什么 C++ 中的第一选择是使用继承,除非你有充分的理由不这样做——这是我在 C++ 职业生涯中从未真正遇到过的。

【讨论】:

谢谢尼尔!...所以这些数据类型基本上无处不在,如果你愿意,它们是一组旋钮。它们可以是 long int、string、bool 等 :( 不能使用继承.. vector 和 C++ 类的问题是你不能声明 Base 的 vector ,然后将 Derived 的实例放入其中。由于 C++ 的复制理念,std::vector(或任何其他 std::container)的任何此类实现都必须使用指针(最终包装的指针)。 @Abhi 实际上你可以使用继承,这就是 boost::any 的工作原理,它将类型擦除到一个私有基础中,该基础具有包含值的模板派生类型,这一切都隐藏在 boost 内部::任何构造函数/赋值运算符都会擦除类型(它们是模板)。但是我建议你重新考虑你的设计,确实需要这个。 感谢 snk_kid!让我暂时使用 boost::any。你是对的,这不是一个好的设计。这是我需要做的 hack,因为我正在开发一个大型建筑模拟器,并且更改设计以使其正确实施将需要大量权限和时间,而我只是在实习期间进行特定的增强.最终这会以正确的方式解决,但到那时我会回到学校! @Abhi 如果您有一组已知类型,我更喜欢使用 boost::variant 并使用静态访问者,这样会更好。【参考方案4】:

我在想你可以只拥有一个 Pair(type, void*) 并编写自己的 pop 函数,根据对中描述的类型投射 void*,然后将它们推入任何吸引你眼球的容器中。

【讨论】:

正如 Neil 提到的那样,容易出错且效率低下,我也不推荐这样做。要么遵循 Neil 的建议,只使用继承,要么查看 boost::any,如 6502 所述。

以上是关于C++如何创建异构容器的主要内容,如果未能解决你的问题,请参考以下文章

您如何定义具有异构值类型的 QHash?

用于异构POD类型的C ++容器

阿里云AI大牛来袭--异构计算与容器技术助力A容器技术助力AI

如何在 C++ 模板容器中实现 erase() 方法

非java异构服务如何集成到SpringCLoud集群中

C++ STL应用与实现2: 如何使用std::vector