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++如何创建异构容器的主要内容,如果未能解决你的问题,请参考以下文章