テンプレートパラメータを使用したアソシエイティブSTLコンテナの統合-コンパレータ

コードを考慮してください:

std::multiset<int> set0, set1; for (auto it = set0.begin(); it != set0.end(); ++it) { //  //  // *it } for (auto it = set1.rbegin(); it != set1.rend(); ++it) { //  //  // *it }
      
      





サイクルの本体での処理は同じです。つまり、2つのマルチセットの要素を同じ方法で処理する必要があります。1つ目は直接の順序、2つ目は逆の順序です。



タスクは、これら2つのサイクルをおよそ次の方法で結合することです。

 size_t const N = 2; std::multiset<int> sets[N] = {/*  ? */}; for (size_t i = 0; i < N; ++i) { for (auto const& val: sets[i]) { //  //  // val } }
      
      





set1処理サイクルでは要素が逆順で並べ替えられ、セット[1]で直接の順序で並べ替えられるため、処理順序を保持するには、セット[1]で要素がset1に対して逆順で格納されることが必要です。 STL連想コンテナでは、テンプレートパラメータが提供されます-コンパレータ、デフォルト値はstd :: lessです。 したがって、最初の近似では、コードを機能させるために、およそ次のようにセットを初期化する必要があります。

 std::multiset<int> sets[N] = {std::multiset<int, std::less>(), std::multiset<int, std::greater>()};
      
      





クラスstd :: multiset <int、std :: less>およびstd :: multiset <int、std :: great>は異なり、共通の祖先がないため、同じ配列に格納できず、コードをコンパイルできません。 (ところで、イテレータstd :: multiset :: const_iteratorおよびstd :: multiset :: const_reverse_iteratorも共通の祖先のない異なるクラスであるため、タスクはイテレータの配列でも解決できません)。 タスクは、コンテナを共通の配列に格納するためのコンテナの統合に要約されます。



STL連想コンテナでは、コンパレータはタイプだけでなく、各コンテナインスタンスのパラメータでもあります。 標準ではstd :: lessのような些細な場合、コンパレータクラスにはデータが含まれないため、すべてのコンテナは同じ比較操作を実行します。特に、要素は同じ順序で格納されます。 より複雑なケースでは、ソート順などのデータをコンパレータに保存できます。 この場合、同じクラスのコンテナの異なるインスタンスは、コンパレータインスタンスのフィールドの値(コンテナインスタンスのフィールド)に応じてアイテムを異なる方法でソートします。 そのため、さまざまな方法で比較できるコンパレータクラス:

 template <typename T> class Comparator { public: bool operator()(const T& l, const T& r) const { return ASC == order_ ? (l < r) : (l > r); } static Comparator const& Asc() { return asc_; } static Comparator const& Desc() { return desc_; } private: enum Order_ {ASC, DESC} const order_; Comparator(Order_ order) : order_(order) {}; static Comparator asc_; static Comparator desc_; }; template<typename T> Comparator<T> Comparator<T>::asc_(Comparator<T>::ASC); template<typename T> Comparator<T> Comparator<T>::desc_(Comparator<T>::DESC);
      
      





実際、このクラスの合計2つのインスタンスがTエレメントのタイプごとに必要であるため、これらの2つのインスタンスは静的に作成され、Comparatorクラスのインターフェースは、これら2つのインスタンス以外は取得できないようになっています(コピーを除く)。



したがって、セットを次のように初期化します。

 typedef std::multiset<int, Comparator<int> > Set; Set sets[N] = { Set(Comparator<int>::Asc()), Set(Comparator<int>::Desc()) };
      
      





したがって、実行可能なソリューションは、連想コンテナの正しい初期化に限定されました。



興味深いことに、コンパレータインスタンスは、ポインタや参照ではなく、値によってコンテナに格納されるため、ソリューションは基本的にポリモーフィックではありません。 ただし、間接的な関数呼び出しに基づいた観点から、動的多型に似たソリューションを提案できます。 以下の機能を検討してください。

 template<typename T> bool compareLess(const T& l, const T& r) { return l < r; } template<typename T> bool compareGreater(const T& l, const T& r) { return l > r; }
      
      





これらは同じ署名、したがって同じ型を持ち、連想コンテナ内のコンパレータの型となる場合があります。 ソリューションは、次の配列の初期化になります。

 typedef bool (*compareFn)(int const&, int const&); typedef std::multiset<int, compareFn> Set2; Set2 sets2[N] = { Set2(compareLess<int>), Set2(compareGreater<int>) };
      
      





UPD: Unrulが std ::関数使用するというアイデアのおかげで、2つのオプションにさらに4つ追加されました。

オプション3:Lyabda関数

オプション4:std :: lessでstd ::関数にラップ、逆ソートの場合、std :: lessのパラメーターはstd :: bindで再配置されます

オプション5:std :: lessおよびstd :: stdで包まれたより大きい::関数

オプション6:オプション2と3を組み合わせます:std ::関数ポインターへの関数キャスト



すべてのソリューションのパフォーマンスを示す完全な例を示します(マルチセットの処理は要素の出力に削減され、正しい並べ替え順序を示します)。

 #include <iostream> #include <set> #include <functional> using namespace std::placeholders; template <typename T> class Comparator { public: bool operator()(const T& l, const T& r) const { return ASC == order_ ? (l < r) : (l > r); } static Comparator const& Asc() { return asc_; } static Comparator const& Desc() { return desc_; } private: enum Order_ {ASC, DESC} const order_; Comparator(Order_ order) : order_(order) {}; static Comparator asc_; static Comparator desc_; }; template<typename T> Comparator<T> Comparator<T>::asc_(Comparator<T>::ASC); template<typename T> Comparator<T> Comparator<T>::desc_(Comparator<T>::DESC); template<typename T> bool compareLess(const T& l, const T& r) { return l < r; } template<typename T> bool compareGreater(const T& l, const T& r) { return l > r; } int main() { static size_t const N = 2; int unsorted[] = {4, 6, 3, 4, 7, 8, 1, 2}; //1 { typedef std::multiset<int, Comparator<int> > Set; Set sets[N] = { Set(Comparator<int>::Asc()), Set(Comparator<int>::Desc()) }; for (size_t i = 0; i < N; ++i) { sets[i].insert(std::begin(unsorted), std::end(unsorted)); } for (size_t i = 0; i < N; ++i) { for (auto const& it : sets[i]) { std::cout << it << " "; } std::cout << "\n"; } } //2 { typedef bool (*compareFn)(int const&, int const&); typedef std::multiset<int, compareFn> Set2; Set2 sets2[N] = { Set2(compareLess<int>), Set2(compareGreater<int>) }; for (size_t i = 0; i < N; ++i) { sets2[i].insert(std::begin(unsorted), std::end(unsorted)); } for (size_t i = 0; i < N; ++i) { for (auto const& it : sets2[i]) { std::cout << it << " "; } std::cout << "\n"; } } //3 { typedef std::multiset<int, std::function<bool(int,int)>> Set3; Set3 sets3[N] = {Set3([](int a, int b){ return a < b; }), Set3([](int a, int b){ return a > b; })}; for (size_t i = 0; i < N; ++i) { sets3[i].insert(std::begin(unsorted), std::end(unsorted)); } for (size_t i = 0; i < N; ++i) { for (auto const& it : sets3[i]) { std::cout << it << " "; } std::cout << "\n"; } } //4 { typedef std::multiset<int, std::function<bool(int,int)>> Set4; Set4 sets4[N] = {Set4(std::less<int>()), Set4(std::bind(std::less<int>(), _2, _1))}; for (size_t i = 0; i < N; ++i) { sets4[i].insert(std::begin(unsorted), std::end(unsorted)); } for (size_t i = 0; i < N; ++i) { for (auto const& it : sets4[i]) { std::cout << it << " "; } std::cout << "\n"; } } //5 { typedef std::multiset<int, std::function<bool(int,int)>> Set5; Set5 sets5[N] = {Set5(std::less<int>()), Set5(std::greater<int>())}; for (size_t i = 0; i < N; ++i) { sets5[i].insert(std::begin(unsorted), std::end(unsorted)); } for (size_t i = 0; i < N; ++i) { for (auto const& it : sets5[i]) { std::cout << it << " "; } std::cout << "\n"; } } //6:   2  3 { typedef bool (*compareFn)(int const&, int const&); typedef std::multiset<int, compareFn> Set6; Set6 sets6[N] = {Set6([](int const& a, int const& b){ return a < b; }), Set6([](int const& a, int const& b){ return a > b; })}; for (size_t i = 0; i < N; ++i) { sets6[i].insert(std::begin(unsorted), std::end(unsorted)); } for (size_t i = 0; i < N; ++i) { for (auto const& it : sets6[i]) { std::cout << it << " "; } std::cout << "\n"; } } return 0; }
      
      






All Articles