異なる特殊なテンプレートクラスを同じメンバー変数に格納するにはどうすればよいですか?

マイク・リシュケ

カスタムハッシャーと比較子を使用してunordered_setに保存したいクラスAがあるとします。このセットを格納するコンテナクラスBもあります。

class B {
private:
  std::unordered_set<A, Hasher, Comparer> set;
};

このコンパイルを行うには、Bをテンプレートクラスにする必要があります。これは、いくつかの主要なリファクタリングにつながり、実際にはこの問題を1層上に移動して、Bのテンプレートパラメーターを処理する必要があるためです。

次に、セットに特化したクラスを作成しようとしました。

class MySet1 : public std::unordered_set<A, MyHasher1, MyComparer1> {
};
class MySet2 : public std::unordered_set<A, MyHasher2, MyComparer2> {
};

クラスBのセット変数に共通のベースクラスがまだないので、明らかにそれは役に立ちません。

これを解決するために、順序付けされていないセットを1レベル下に移動しました。

class MySet {
public:
  // Some abstract functions...
};

class MySet1 : public MySet {
public:
  // Implementation of the abstract functions.
private:
  std::unordered_set<A, MyHasher1, MyComparer1> set;
};

class MySet2 : public MySet {
public:
  // Implementation of the abstract functions.
private:
  std::unordered_set<A, MyHasher2, MyComparer2> set;
};

これで、クラスBに共通の基本クラス(MySet)ができました。しかし、明らかな欠点は次のとおりです。各セットの特殊化に対するコードの重複と、セットをSTLで機能させるためにカスタムイテレーターを実装する必要があります。これが私が立ち止まって、私が実際に望んでいることを達成するためのより良い方法があるかどうかを自問したところです。同じメンバーvarに異なるunordered_setクラスを格納し、そのvarの所有者もテンプレート化する必要はありません。

gluk47

本旨

ここでは、多重継承を喜んで採用できます。

主なアイデアは、セットにタグを付ける基本クラスを作成し、それをすべてのセットの基本クラスにすることです。次に、必要な各テンプレート引数のセットクラスを明示的にインスタンス化し、セットコンテナとタグ付けインターフェイスの両方からパブリックに継承された空のクラスを作成します。そうすれば、追加するものは何もありません。コードの複製は必要ないようです。

とにかく、すべてのテンプレートの特殊化で機能するいくつかの(おそらく仮想)関数を作成する必要があります。保持するものに関係なく、同じコンテキストで単一の変数を使用できる必要があります。ただしusing、継承のために宣言を増やして一部のコードを減らし、暗黙的な型変換を使用することができます(たとえば、セットに数値のみが含まれている場合)。

#include <set>

class setInterface {
    /* Code common for all set template specializations
       (you have to have some common interface anyway) */
};

template <typename T> class TSet: public setInterface, std::set<T> {
    using std::set<T>::set;
    /* more using-declarations or templated versions of some functions
       You can use SFINAE here to achieve more magical results,
       or use template specializations for specific types. */
};

using intSet = TSet<int>;
using doubleSet = TSet<double>;

class B {
public:
  setInterface values;
};

int main () {
    B b;
    b.values = intSet {1, 2, 3} ;
    b.values = doubleSet {1., 2., 3.};
}

PS:構文を使用したテンプレートを提供してくれた@ Jarod42に感謝します。

実用的な実装

以下の仮定がなされています。

  • に変換可能なアイテムのセットのみを使用しlong longます。void*一般的なケースで使用し、利便性/安全性のためにいくつかの追加メソッドを追加できます
  • 私たちは正気であり、異なるタイプのセットのイテレータを比較することは決してありません。結果は予測できません。
  • nullptrsのポインタをチェックする必要はありません(まあ、それは私のコードサンプルにそれ以上の価値をもたらさないでしょう、確かにあなたが常に必要とする現実の世界では)。

このソリューションは、非定数の開始/終了を使用し、の新しい光沢のある範囲ベースを使用して、マップを反復処理できます。main;を参照してくださいコンパイルして実行し(-std=c++14)、結果を確認します。

#include <set>
#include <memory>
#include <iostream>

using common_denominator_type = long long;

class setInterface {
protected:
    class iterator_impl;
public:
    class iterator {
    public:
        iterator (iterator_impl* impl) : impl (impl) {}

        iterator& operator++ () { ++*impl; return *this; };
        bool operator != (const iterator& rhs) const { return *impl != *rhs.impl; };
        common_denominator_type operator* () const { return **impl; };
    private:
        std::shared_ptr <iterator_impl> impl;
    };
    virtual iterator begin() = 0;
    virtual iterator end() = 0;
    virtual size_t size() const = 0;
protected:
    class iterator_impl {
    public:
        virtual iterator_impl& operator++ () = 0;
        virtual bool operator != (const iterator_impl&) const = 0;
        virtual common_denominator_type operator* () const = 0;
        virtual void* as_std_set_iterator () = 0;
        virtual const void* as_std_set_iterator () const = 0;
    };
};

template <typename T> class TSet: public setInterface, std::set<T> {
public:
    using std::set<T>::set;
    size_t size () const override { return std::set<T>::size(); }
    iterator begin () override { return iterator (new TSet<T>::iterator_impl (std::set<T>::begin())); }
    iterator end   () override { return iterator (new TSet<T>::iterator_impl (std::set<T>::end  ())); }
protected:
    class iterator_impl: public setInterface::iterator_impl {
    public:
        using std_it = typename std::set<T>::iterator;
        iterator_impl (std_it&& _) : m_real_iterator(std::move (_)) {}
        iterator_impl& operator++ () override { ++m_real_iterator; return *this; }
        bool operator != (const setInterface::iterator_impl& rhs) const override {
            return *reinterpret_cast <const std_it*>(as_std_set_iterator())
                    !=
                   *reinterpret_cast <const std_it*>(rhs.as_std_set_iterator());
        }
        common_denominator_type operator* () const override { return *m_real_iterator; }
        void* as_std_set_iterator () override { return &m_real_iterator; }
        const void* as_std_set_iterator () const override { return &m_real_iterator; }
    private:
        std_it m_real_iterator;
    };
};

using intSet = TSet<int>;
using longSet = TSet<long>;

class B {
public:
    std::shared_ptr <setInterface> values;
};

std::ostream& operator<< (std::ostream& str, B& b) {
    str << "[" << b.values->size() << "] [";
    for (auto i = b.values->begin(); i != b.values->end(); ++i)
        str << *i << " ";
    str << "][";
    for (auto i : *b.values)
        str << i << " ";
    return str << "]";
}

int main () {
    B b;
    b.values.reset (new intSet {1, 2, 3});
    std::cout << b << std::endl;
    b.values.reset (new longSet {10l, 20l, 30l});
    std::cout << b << std::endl;
}

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

異なるテンプレートパラメータを持つ変数でベクトルを作成するにはどうすればよいですか?

分類Dev

同じクラスでテンプレート引数が異なるこの演算子のオーバーロードを修正するにはどうすればよいですか?

分類Dev

テンプレート化されていないクラスのテンプレート化されたメンバーメソッドを部分的に特殊化するにはどうすればよいですか?

分類Dev

クラスを特殊化する場合、異なる数のテンプレートパラメータを取得するにはどうすればよいですか?

分類Dev

Djangoの異なるディレクトリで同じ名前のテンプレートを呼び出すにはどうすればよいですか?

分類Dev

Djangoの異なるディレクトリで同じ名前のテンプレートを呼び出すにはどうすればよいですか?

分類Dev

ifステートメント変数が関数と同じになるように設定するにはどうすればよいですか

分類Dev

この例では、同じインターフェイスから継承するさまざまなオブジェクトをジェネリック型で1つの変数に格納するにはどうすればよいですか?

分類Dev

同じ変数を異なるクラスで変更するにはどうすればよいですか?

分類Dev

C ++の特殊なテンプレートクラスのテンプレートクラスメンバーフィールドにアクセスするにはどうすればよいですか?

分類Dev

STLコンテナであるテンプレートパラメータに基づいて、選択したメンバー関数の部分的な特殊化をシミュレートするにはどうすればよいですか?

分類Dev

可変個引数テンプレート-渡された引数を格納する型を作成するにはどうすればよいですか

分類Dev

同じCorDappで2つの異なるレスポンダーフローをテストするにはどうすればよいですか?

分類Dev

そのようなメソッドを持たない親クラスのオブジェクトとして格納されている場合、クラスのメンバーにアクセスするにはどうすればよいですか?

分類Dev

同じアプリで異なる環境のユニバーサルリンクをサポートするにはどうすればよいですか?

分類Dev

同じアプリで異なる環境のユニバーサルリンクをサポートするにはどうすればよいですか?

分類Dev

Rの異なるマップのポイントに同じカラースケールを使用するにはどうすればよいですか?

分類Dev

セレンPythonで同じクラスから異なるデータを取得するにはどうすればよいですか?

分類Dev

完全に特殊化されたテンプレートクラスの定義の外でテンプレートメンバー関数を定義するにはどうすればよいですか?

分類Dev

完全に特殊化されたテンプレートクラスの定義の外でテンプレートメンバー関数を定義するにはどうすればよいですか?

分類Dev

同じコンポーネントに異なるサービストークンを挿入するにはどうすればよいですか?

分類Dev

同じテンプレート関数で複数のタイプを特殊化するにはどうすればよいですか?

分類Dev

部分的なクラステンプレートの特殊化で継承を実装するにはどうすればよいですか?

分類Dev

C ++の複数のクラスタイプに同じテンプレートメンバー関数を指定するにはどうすればよいですか?

分類Dev

同じアクティビティ内のフラグメントごとに異なるMenuItemを使用するにはどうすればよいですか?

分類Dev

同じユーティリティスクリプトが異なるSCMディレクトリにチェックインされていても、どこでも同じである必要がある場合、それらが同じであることを確認するにはどうすればよいですか?

分類Dev

スリングスレッドプール内の複数のスレッドが同じステートメントを実行しないようにするにはどうすればよいですか?

分類Dev

関数テンプレート(クラステンプレートのメンバー)を明示的に特殊化すると、「部分的な特殊化は許可されていません」というエラーが発生します。なぜですか?

分類Dev

同じインストールで2つの異なるバージョンのワインを使用するにはどうすればよいですか?

Related 関連記事

  1. 1

    異なるテンプレートパラメータを持つ変数でベクトルを作成するにはどうすればよいですか?

  2. 2

    同じクラスでテンプレート引数が異なるこの演算子のオーバーロードを修正するにはどうすればよいですか?

  3. 3

    テンプレート化されていないクラスのテンプレート化されたメンバーメソッドを部分的に特殊化するにはどうすればよいですか?

  4. 4

    クラスを特殊化する場合、異なる数のテンプレートパラメータを取得するにはどうすればよいですか?

  5. 5

    Djangoの異なるディレクトリで同じ名前のテンプレートを呼び出すにはどうすればよいですか?

  6. 6

    Djangoの異なるディレクトリで同じ名前のテンプレートを呼び出すにはどうすればよいですか?

  7. 7

    ifステートメント変数が関数と同じになるように設定するにはどうすればよいですか

  8. 8

    この例では、同じインターフェイスから継承するさまざまなオブジェクトをジェネリック型で1つの変数に格納するにはどうすればよいですか?

  9. 9

    同じ変数を異なるクラスで変更するにはどうすればよいですか?

  10. 10

    C ++の特殊なテンプレートクラスのテンプレートクラスメンバーフィールドにアクセスするにはどうすればよいですか?

  11. 11

    STLコンテナであるテンプレートパラメータに基づいて、選択したメンバー関数の部分的な特殊化をシミュレートするにはどうすればよいですか?

  12. 12

    可変個引数テンプレート-渡された引数を格納する型を作成するにはどうすればよいですか

  13. 13

    同じCorDappで2つの異なるレスポンダーフローをテストするにはどうすればよいですか?

  14. 14

    そのようなメソッドを持たない親クラスのオブジェクトとして格納されている場合、クラスのメンバーにアクセスするにはどうすればよいですか?

  15. 15

    同じアプリで異なる環境のユニバーサルリンクをサポートするにはどうすればよいですか?

  16. 16

    同じアプリで異なる環境のユニバーサルリンクをサポートするにはどうすればよいですか?

  17. 17

    Rの異なるマップのポイントに同じカラースケールを使用するにはどうすればよいですか?

  18. 18

    セレンPythonで同じクラスから異なるデータを取得するにはどうすればよいですか?

  19. 19

    完全に特殊化されたテンプレートクラスの定義の外でテンプレートメンバー関数を定義するにはどうすればよいですか?

  20. 20

    完全に特殊化されたテンプレートクラスの定義の外でテンプレートメンバー関数を定義するにはどうすればよいですか?

  21. 21

    同じコンポーネントに異なるサービストークンを挿入するにはどうすればよいですか?

  22. 22

    同じテンプレート関数で複数のタイプを特殊化するにはどうすればよいですか?

  23. 23

    部分的なクラステンプレートの特殊化で継承を実装するにはどうすればよいですか?

  24. 24

    C ++の複数のクラスタイプに同じテンプレートメンバー関数を指定するにはどうすればよいですか?

  25. 25

    同じアクティビティ内のフラグメントごとに異なるMenuItemを使用するにはどうすればよいですか?

  26. 26

    同じユーティリティスクリプトが異なるSCMディレクトリにチェックインされていても、どこでも同じである必要がある場合、それらが同じであることを確認するにはどうすればよいですか?

  27. 27

    スリングスレッドプール内の複数のスレッドが同じステートメントを実行しないようにするにはどうすればよいですか?

  28. 28

    関数テンプレート(クラステンプレートのメンバー)を明示的に特殊化すると、「部分的な特殊化は許可されていません」というエラーが発生します。なぜですか?

  29. 29

    同じインストールで2つの異なるバージョンのワインを使用するにはどうすればよいですか?

ホットタグ

アーカイブ