web-dev-qa-db-ja.com

C ++での異種コンテナー

次のようなデータのさまざまな要件に基づいて、どのSTLコンテナが適しているかを分類するこの素晴らしいグラフィックを見ました。

-固定サイズと可変サイズ

-同じタイムと異なるタイプのデータ

-ソート済みデータと未ソートデータ

-順次アクセスとランダムアクセス

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

その画像で、C++ STLにはコンテナがないことに気付きました

  1. 可変サイズ
  2. 異種(異なるタイプのデータ)。

C++にはこれがないのですか?

PS-コンテナのさまざまなプロパティから作成された多くの順列があり、他の多くもSTLで提供されない場合があります。

23
goldenmean

一般的に、C++コンテナーは、テンプレートを使用して単一タイプのオブジェクトを保持するように設計されています。すべてが1つの型から派生した異なる型が必要な場合は、ポインターのコンテナーを格納できます(おそらく、void *のコンテナーを何にでも持つことができると思います...)。 std :: vector <MyBaseType *>。

まったく関係のない型が必要な場合は、boost :: anyなど、他の型を安全に参照できるオブジェクトを格納できます。

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

ブーストサイトの例:

#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
17
Fire Lancer

標準ライブラリの基本原則は、「コンテナ」は同種であるということです。 C++標準では、std::pairstd::Tupleのようなものはコンテナーとは見なされません。 (グラフはコンテナーと見なされるため、誤解を招くと考えます。)異種コンテナーが必要な場合は、boost::variantのコンテナー、またはそれらの線に沿ったものを使用する必要があります。

10
James Kanze

std::pairstd::Tupleは、ほとんどC++コンテナではありません。..いいえ、STLに異種コンテナはありません。組み込みにする必要がないためです。

このようなコンテナーを作成する方法はいくつかあります。私がお勧めするアプローチは次のとおりです。

  • ポリモーフィズムの使用
  • バリアント型を使用する

ポリモーフィズムについては、 Boost Pointer Container ライブラリを確認できます。

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;を指定すると、*itBase&になります

タイプが無関係である場合、他の可能性は Boost Variant を使用することです。基本的に、バリアントは次のようになります。

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

もちろん、ブーストであるため、現在アクティブなユニオンのメンバーにのみアクセスできることを保証し、コンストラクター/デストラクタが従来のユニオンで使用できないクラスの制限を解除するための特定の保証を提供します。

また、static_visitorのような機能も提供します。これは、タイプのスイッチと同等であり、考えられる状態の1つにアクセスしないと、コンパイルエラーが発生します。

4
Matthieu M.

Boostにまだ受け入れられていないライブラリ。しかし、インクルージョンのために提案されたものはこれに向けられています:

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

これは、any_collectionという名前のNiceクラスを提供します。これにより、boost :: type_erasure :: any: http://rawgit.com/joaquintides/poly_collection/website/doc/html/poly_collection/tutorial。 html#poly_collection.tutorial.basics.boost_any_collection

それ以外の場合、C++ 17ではこれを実装する簡単な方法があります: https://gieseanw.wordpress.com/2017/05/03/a-true-heterogeneous-container-in-c/

前述の記事の例を引用すると、

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{});

著者はそれがおもちゃの実装であると述べていますが、これはそれを実装する本当に賢い方法であり、poly_collectionまたはバリアントのベクトルよりも単純な利点があると思います。

3
daminetreg

固定サイズの異機種コンテナー(std::Tupleなど)では、コンパイル時に型がわかっている必要があります。可変サイズの異機種コンテナーを作成する場合は、std::vector<std::Tuple<T1,T2,...,TN>>を作成します。

型がコンパイル時に不明である異種コンテナが必要な場合(それが可変サイズか固定サイズかに関係なく)、コンパイル時に既知の基本型へのポインター(またはスマートポインター)を格納するか、あるいは何かを検討する必要がありますboost::anyのコンテナのように。 STLは、実行時に決定される異種の要素を持つ固定サイズまたは可変サイズのこのようなコンテナーを直接提供しません。

2
Clinton

保存する要素が boost::any または boost::variant すると、異種のデータを間接的に保存できます。

1
dalle

このライブラリを紹介します。これは、真の異種コンテナーであるように実装されています 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));
0
hmoein