26

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

-- 固定尺寸与可变尺寸

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

-- 已排序数据与未排序数据

-- 顺序访问与随机访问

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

我注意到在那张图片中,C++ STL 没有容器

  1. 可变大小
  2. 异构(不同类型的数据)。

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

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

4

7 回答 7

20

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

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

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

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 类似,但您指定了所有允许的类型,而不是允许容器中的任何类型。

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
于 2011-10-18T09:23:05.107 回答
10

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

于 2011-10-18T09:22:29.103 回答
5

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

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

Otherwise in C++17 there are simple way to implement this : 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.

于 2017-05-12T13:08:20.270 回答
4

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

有几种方法可以创建这样的容器。我推荐的方法是:

  • 使用多态性
  • 使用变体类型

对于多态性,您可以检查Boost Pointer Container library。

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

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

  • 访问元素为Base&
  • 自动内存处理
  • 具体复制行为(使用new_clone方法)
  • 语法糖:给定boost::ptr_vector<Base>::iterator it;*it是一个Base&

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

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

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

它还提供了类似 的工具static_visitor,它相当于类型上的开关,并且如果未访问其中一种可能的状态,则编译错误。

于 2011-10-18T09:44:32.603 回答
2

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

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

于 2011-10-18T09:25:27.123 回答
1

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

于 2011-10-18T09:21:08.847 回答
1

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

你可以写这样的代码

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));
于 2020-01-02T16:19:47.770 回答