C++ C+中的异构容器+;

C++ C+中的异构容器+;,c++,stl,containers,heterogeneous,C++,Stl,Containers,Heterogeneous,我看到了这个漂亮的图形,它根据不同的数据要求对STL容器进行分类,例如: --固定大小与可变大小 --相同类型与不同类型的数据 --已排序与未排序的数据 --顺序存取与随机存取 我注意到,在那个图像中,C++ STL没有容器是 可变尺寸 异构(不同类型的数据) C++没有什么东西吗?< /P> PS-容器的不同属性可能有许多排列,STL中也可能没有提供许多其他排列。如果存储的元素是a,则可以间接存储异构数据。标准库的基本原则是“容器”是同质的;C++标准不考虑诸如“代码> STD::配对<

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

--固定大小与可变大小

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

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

--顺序存取与随机存取

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

  • 可变尺寸
  • 异构(不同类型的数据)

    C++没有什么东西吗?< /P>


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

    如果存储的元素是a,则可以间接存储异构数据。

    标准库的基本原则是“容器”是同质的;C++标准不考虑诸如“代码> STD::配对< /Calp>或<代码> STD::tuple < /Cord>作为容器。(我认为图表是误导性的,因为它把它们当作容器)。如果你需要一个异构容器,你就必须使用一个容器:<代码> Boo::变体或者沿着这些线的东西。

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

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

    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::any_cast;
    typedef std::列出许多;
    void append_int(多个&值,int值)
    {
    boost::any to_append=值;
    值。向后推_(以追加_);
    }
    void append_字符串(多个和值,常量std::字符串和值)
    {
    值。推回(值);
    }
    bool is_int(常量boost::any&操作数)
    {
    返回操作数.type()==typeid(int);
    }
    bool是字符(const boost::any&操作数)
    {
    尝试
    {
    任意_转换(操作数);
    返回true;
    }
    捕获(常量增强::坏的\u任何\u投射&)
    {
    返回false;
    }
    }
    
    variant与之类似,但您指定了所有允许的类型,而不是允许容器中的任何类型

    std::vectorvec;
    向量推回(44);
    向量推回(“str”);
    向量推回(SomthingElse(55,65))//不准
    
    固定大小的异构容器(如
    std::tuple
    要求在编译时知道类型。如果要创建可变大小的异构容器,只需创建一个
    std::vector


    如果您想要一个在编译时类型未知的异构容器(无论是可变的还是固定大小的),您必须存储指针(或智能指针)对于编译时已知的一种基类型,或者考虑一个容器,如“代码>升压::任何< /COD>”。STL不直接提供固定的或可变大小的容器,它在运行时确定了不同的元素。

    <代码> STD::配对< /C> >和<>代码> STD::tuple < /C> >几乎不是C++容器……所以不,STL中没有异构容器,因为不需要内置它们

    创建此类容器有几种方法。我推荐的方法有:

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

    对于多态性,您可以检查库

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


    它还提供了类似于打开类型开关的
    static\u visitor
    等功能,如果其中一个可能的状态未被访问,则会导致编译错误。

    一个尚未被Boost接受的库。但建议包含的库旨在:

    它提供了一个名为any_collection的好类,它允许通过boost::type_erasure::any拥有一个异构容器:

    否则,在C++17中,有一种简单的方法可以实现这一点:

    引用上述文章的例子:

    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
    

    作者说这是一个玩具式的实现,但我认为这是一个非常聪明的实现方式,与poly_集合或变量向量相比,它有一个简单的优势。

    我将向您指出这个库。它被实现为真正的异构容器 它不使用多态性,因此也不存储指针。它使用连续内存存储,就像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));
    
    typedef StdDataFrame MyDataFrame;
    MyDataFrame-df;
    std::vector intvec={1,2,3,4,5};
    向量dblvec={1.2345,2.2345,3.2345,4.2345,5.2345};
    向量dblvec2={0.998,0.3456,0.056,0.15678,0.00345,
    0.923, 0.06743, 0.1 };
    std::vector strvec={“洞察”、“约翰·道”、“阿拉卡萨姆”,
    “波斯王子”、“兔八哥”};
    std::vector ulgvec={1UL,2UL,3UL,4UL,5UL,8UL,7UL,6UL}
    std::vector xulgvec=ulgvec;
    //这只是将数据加载到DataFrame实例中的一种方法
    //有很多不同的方法。请参阅文档,
    //或dataframe_tester.cc
    int rc=df.load_data(std::move(ulgvec))//索引列
    std::制作成对(“int col”,intvec),
    标准::制作双(“dbl\U列”,dblvec),
    标准::制作双(“dbl\U列2”,dblvec2),
    标准::制作成对(“str_col”,strvec),
    std::make_pair(“ul_col”,xulgvec));
    
    从这张图片中,我可以看出其中有那么多
    enum { Type1, Type2, ... } _type;
    union {
      SomeType1 _1;
      SomeType2 _2;
      ...
    } _u;
    
    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
    
    andyg::heterogeneous_container c;
    c.push_back(1);
    c.push_back(2.f);
    c.push_back('c');
    struct LocalStruct{};
    c.push_back(LocalStruct{});
    
    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));