C++ 中的异构容器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7804955/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:31:05  来源:igfitidea点击:

Heterogeneous containers in C++

c++stlcontainersheterogeneous

提问by goldenmean

I saw this nice graphic which classifies which STL container would suit based on different requirements of data such as:

我看到了这个漂亮的图形,它根据不同的数据要求对适合哪种 STL 容器进行分类,例如:

-- Fixed Size Vs Variable size

-- 固定大小与可变大小

-- Data of same tyme Vs different type

-- 相同类型的数据与不同类型的数据

-- Sorted Vs unsorted data

-- 排序与未排序的数据

-- Sequential Vs random access

-- 顺序访问与随机访问

http://plasmahh.projectiwear.org/cce_clean.svg

http://plasmahh.projectiwear.org/cce_clean.svg

I notice in that image, that C++ STL there is no container which is

我注意到在那个图像中,C++ STL 没有容器是

  1. Variable Size
  2. Heterogenous (data of different types).
  1. 可变尺寸
  2. 异构(不同类型的数据)。

Doesn't C++ have something for this?

C++ 没有这方面的东西吗?

PS - There can be many permutations made out the different properties of the containers and many others too might not be provided in STL.

PS - 容器的不同属性可以有许多排列,STL 中可能没有提供许多其他排列。

采纳答案by Fire Lancer

Well generally C++ Containers are designed to hold objects of a single type using templates. If you want different types that are all derived from one type you can store a container of pointers (I guess you could also have a container of void* to anything...) e.g. std::vector<MyBaseType*>.

一般而言,C++ 容器被设计为使用模板保存单一类型的对象。如果你想要从一种类型派生的不同类型,你可以存储一个指针容器(我猜你也可以有一个 void* 容器......)例如 std::vector<MyBaseType*>。

If you want completely unrelated types, you can store objects that can safely reference those other types, such as boost::any.

如果你想要完全不相关的类型,你可以存储可以安全地引用那些其他类型的对象,比如 boost::any。

http://www.boost.org/doc/libs/1_47_0/doc/html/any.html

http://www.boost.org/doc/libs/1_47_0/doc/html/any.html

Some examples off the boost site:

boost网站上的一些示例:

#include <list>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::list<boost::any> many;

void append_int(many & values, int value)
{
    boost::any to_append = value;
    values.push_back(to_append);
}

void append_string(many & values, const std::string & value)
{
    values.push_back(value);
}

bool is_int(const boost::any & operand)
{
    return operand.type() == typeid(int);
}
bool is_char_ptr(const boost::any & operand)
{
    try
    {
        any_cast<const char *>(operand);
        return true;
    }
    catch(const boost::bad_any_cast &)
    {
        return false;
    }
}

boost::variant is similar, but you specify all the allowed types, rather than allowing any type in your container.

boost::variant 类似,但您指定所有允许的类型,而不是允许容器中的任何类型。

http://www.boost.org/doc/libs/1_47_0/doc/html/variant.html

http://www.boost.org/doc/libs/1_47_0/doc/html/variant.html

std::vector< boost::variant<unsigned, std::string> > vec;
vec.push_back( 44);
vec.push_back( "str" );
vec.push_back( SomthingElse(55, 65) ); //not allowed

回答by James Kanze

The basic principle in the standard library is that "containers" are homogeneous; the C++ standard doesn't consider things like std::pairor std::tupleto be containers. (I'd consider the graph misleading, since it does consider them as containers.) If you need a heterogeneous container, you'd have to use a container of boost::variant, or something along those lines.

标准库的基本原则是“容器”是同构的;C++ 标准不考虑容器之类的东西std::pairstd::tuple容器。(我认为该图具有误导性,因为它确实将它们视为容器。)如果您需要一个异构容器,则必须使用 的容器boost::variant或类似的东西。

回答by Matthieu M.

std::pairand std::tupleare hardly C++ containers.... so no, there is no heterogeneous containers in the STL, because it's not necessary to have them built-in.

std::pair并且std::tuple几乎不是 C++ 容器......所以不,STL 中没有异构容器,因为没有必要将它们内置。

There are several approaches to create such containers. The approaches I would recommend are:

有多种方法可以创建此类容器。我推荐的方法是:

  • using polymorphism
  • using a variant type
  • 使用多态
  • 使用变体类型


For Polymorphism, you can check Boost Pointer Containerlibrary.

对于多态性,您可以查看Boost Pointer Container库。

boost::ptr_vector<Base> vec;
vec.push_back(new Derived);
vec.push_back(new Derived2);

It mimicks the STL containers, but provides functionalities geared toward polymorphism:

它模仿了 STL 容器,但提供了面向多态的功能:

  • Access elements as Base&
  • Automatic memory handling
  • Specific copy behavior (using new_clonemethods)
  • Syntactic sugar: given boost::ptr_vector<Base>::iterator it;, *itis a Base&
  • 访问元素为 Base&
  • 自动内存处理
  • 特定的复制行为(使用new_clone方法)
  • 语法糖:给定boost::ptr_vector<Base>::iterator it;*it是一个Base&


If your types are unrelated, the other possibility is to use Boost Variant. Basically, a variant is similar to:

如果您的类型不相关,另一种可能是使用Boost Variant。基本上,变体类似于:

enum { Type1, Type2, ... } _type;
union {
  SomeType1 _1;
  SomeType2 _2;
  ...
} _u;

Of course, since it's boost, it provides specific guarantees to make sure that you can only access the member of the union that is currently active and lifts the restriction on classes with constructors / destructors not being usable in traditional unions.

当然,由于它是 boost,它提供了特定的保证,以确保您只能访问当前活动的联合成员,并解除对构造函数/析构函数在传统联合中不可用的类的限制。

It also provides facilities, like the static_visitor, which is the equivalent of a switch on the type, and will make the compilation error out if one of the possible states is not visited.

它还提供了一些工具,比如static_visitor,它相当于类型上的一个开关,如果没有访问可能的状态之一,它将导致编译错误。

回答by daminetreg

A library which is not yet accepted into Boost. But which was proposed for inclusion is targeted toward this :

尚未被 Boost 接受的库。但提议列入的内容是针对此的:

http://rawgit.com/joaquintides/poly_collection/website/doc/html/index.html

http://rawgit.com/joaquintides/poly_collection/website/doc/html/index.html

It provides a nice class named any_collection which allows one to have an heterogeneous container via boost::type_erasure::any : http://rawgit.com/joaquintides/poly_collection/website/doc/html/poly_collection/tutorial.html#poly_collection.tutorial.basics.boost_any_collection

它提供了一个名为 any_collection 的好类,它允许通过 boost::type_erasure::any 拥有一个异构容器:http://rawgit.com/joaquintides/poly_collection/website/doc/html/poly_collection/tutorial.html#poly_collection 。 tutorial.basics.boost_any_collection

Otherwise in C++17 there are simple way to implement this : https://gieseanw.wordpress.com/2017/05/03/a-true-heterogeneous-container-in-c/

否则在 C++17 中有简单的方法来实现这个:https: //gieseanw.wordpress.com/2017/05/03/a-true-heterogeneous-container-in-c/

Quoting the example of the aforementioned article :

引用上述文章的例子:

namespace andyg{
struct heterogeneous_container{
private:
    template<class T>
    static std::unordered_map<const heterogeneous_container*, std::vector<T>> items;
public:
    template <class T>
    void push_back(const T& _t)
    {
        items<T>[this].push_back(_t);
    }
};

// storage for our static members
template<class T>
std::unordered_map<const heterogeneous_container*, std::vector<T>> heterogeneous_container::items;
} // andyg namespace

Then usable easily :

然后可以轻松使用:

andyg::heterogeneous_container c;
c.push_back(1);
c.push_back(2.f);
c.push_back('c');
struct LocalStruct{};
c.push_back(LocalStruct{});

The author states it's a toy implementation, but I think this is a really clever way to implement it, and has a simplicity advantage over poly_collection or a vector of variants.

作者声明这是一个玩具实现,但我认为这是一个非常聪明的实现方式,并且比 poly_collection 或变体向量具有简单的优势。

回答by Clinton

The fixed size heterogenous containers (like std::tuplerequire the types to be known at compile time. If you want to make a variable sized heterogeneous container, just make a std::vector<std::tuple<T1,T2,...,TN>>.

固定大小的异构容器(比如std::tuple需要在编译时知道类型。如果你想制作一个可变大小的异构容器,只需制作一个std::vector<std::tuple<T1,T2,...,TN>>.

If you want a heterogeneous container where the types is not known at compile time (whether that would be variable or fixed sized) you'll have to store pointers (or smart pointers) to a base type known at compile time, or alternatively consider something like a container of boost::any. The STL doesn't directly provide such a container in either fixed or variable sized with heterogeneous elements determined at run time.

如果您想要一个在编译时未知类型的异构容器(无论是可变的还是固定大小的),您必须将指针(或智能指针)存储到编译时已知的基类型,或者考虑一些东西就像一个容器boost::any。STL 不直接提供大小固定或可变的容器,其中包含在运行时确定的异构元素。

回答by dalle

If the element you store would be a boost::anyor boost::variantthen you can indirectly store heterogeneous data.

如果您存储的元素是 a boost::anyorboost::variant那么您可以间接存储异构数据。

回答by hmoein

I would point you to this library. It is implemented to be true heterogeneous container https://github.com/hosseinmoein/DataFrameIt does not use polymorphism and consequently store pointers. It uses continuous memory storage, just like a std::vector.

我会向你指出这个图书馆。它被实现为真正的异构容器 https://github.com/hosseinmoein/DataFrame它不使用多态性,因此不存储指针。它使用连续内存存储,就像 std::vector 一样。

You can write code like this

你可以写这样的代码

typedef StdDataFrame<unsigned long> MyDataFrame;

MyDataFrame                df;
std::vector<int>           intvec = { 1, 2, 3, 4, 5 };
std::vector<double>        dblvec = { 1.2345, 2.2345, 3.2345, 4.2345, 5.2345 };
std::vector<double>        dblvec2 = { 0.998, 0.3456, 0.056, 0.15678, 0.00345,
                                       0.923, 0.06743, 0.1 };
std::vector<std::string>   strvec = { "Insight", "John Dow", "Alakazam",
                                      "Persian Prince", "Bugs Bunny" };
std::vector<unsigned long> ulgvec = { 1UL, 2UL, 3UL, 4UL, 5UL, 8UL, 7UL, 6UL }
std::vector<unsigned long> xulgvec = ulgvec;

// This is only one way of loading data into a DataFrame instance. There are
// many different ways of doing it. Please see the documentation,
// or dataframe_tester.cc
int rc = df.load_data(std::move(ulgvec),  // Index column
                      std::make_pair("int_col", intvec),
                      std::make_pair("dbl_col", dblvec),
                      std::make_pair("dbl_col_2", dblvec2),
                      std::make_pair("str_col", strvec),
                      std::make_pair("ul_col", xulgvec));