6

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

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

4

4 回答 4

10

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
}
于 2010-07-09T16:19:41.303 回答
7

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

于 2010-07-09T11:21:09.277 回答
4

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

于 2010-07-09T11:25:58.393 回答
0

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

于 2010-07-09T11:24:46.210 回答