5

次のようなテンプレート化されたコンテナ クラスがあります。

template<
   class KeyType, 
   class ValueType, 
   class KeyCompareFunctor   = AnObnoxiouslyLongSequenceOfCharacters<KeyType>, 
   class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType> 
>
   class MyClass
   {
      [...]
   }

つまり、このクラスのオブジェクトをインスタンス化する場合、いくつかの異なる方法で実行できます。

MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;

それらはすべて良いです。問題は、デフォルト以外のバージョンの ValueCompareFunctor 引数を使用する MyClass をインスタンス化したいが、それでも KeyCompareFunctor 引数のデフォルト値を使用したい場合に発生します。それから私はこれを書かなければなりません:

MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;

何とかして 3 番目の引数を省略して、次のように書くことができれば、はるかに便利です。

MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;

MyCustomValueCompareFunctor は、MyValueType 型のオブジェクトに対してのみ機能し、MyKeyType 型のオブジェクトに対しては機能しないため、コンパイラは少なくとも理論的には、ここで説明したことを理解できるようです。

C++でこれを行う方法はありますか?

4

5 に答える 5

5

一般に、テンプレートと関数またはメソッドの両方で、C++ では末尾のパラメーターのみにデフォルトを使用 (したがって省略) できます。

AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>短縮するテンプレートまたはマクロをお勧めしますFoo<MyKeyType>-- 完璧ではありませんが、何もないよりはましです。

于 2009-08-01T04:39:29.527 に答える
4

voidいいえ、最も近いのは、ユーザーが「ここでデフォルト値を使用する」という意味のセンチネルタイプを指定できるようにし、クラス内でテンプレートメタマジックを使用してtypedef、実際のデフォルトvoidが与えられた場合に使用できるようにすることです。しかし、これはおそらく読みやすさの観点からは良い考えではありません。

于 2009-08-01T04:39:01.243 に答える
3

ブースト パラメーターブースト グラフの名前付きパラメーターは、テンプレート関数/メソッドのパラメーターに名前を付けるための取り組みです。それらは、好きな順序で引数を提供する機会を与えます。一部の引数は省略可能で、デフォルト値があります。

テンプレート引数にも同じアプローチを適用できます。N 個のテンプレート引数 + P 個のオプションの引数を使用する代わりに、N+1 個のテンプレート引数を使用してクラスを作成します。最後のパラメータは、省略可能な「名前付き」パラメータを保持します。

この回答はまだ完全ではありませんが、良いスタートになることを願っています!

于 2009-08-01T09:38:28.033 に答える
0

別のオプションは、Traits クラスを使用することです。

template <class KeyType>
class KeyTraits
{
  typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> Compare;
};

template <class ValueType>
class ValueTraits
{
  typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>  Compare;
};

template<class KeyType class ValueType>
class MyClass
{
  typedef KeyTraits<KeyType>::Compare KeyCompareFunctor;
  typedef ValueTraits<ValueType>::Compare KeyCompareFunctor;
};

次に、キーの別の比較関数が必要な型がある場合は、その場合に KeyTraits 型を明示的に特殊化します。に変更する例を次に示しますint

template <>
class KeyTraits<int>
{
  typedef SpecialCompareForInt Cmopare;
};
于 2009-08-03T10:29:45.517 に答える
0

継承を使用し、次のように機能する別のオプションがあります。最後の 2 つの引数については、必要な型を生成するために使用できる 2 つのメンバー テンプレートを持つクラスから仮想的に継承するクラスを使用します。継承は仮想であるため、宣言する typedef は、以下に示すように継承間で共有されます。

template<class KeyType, 
         class ValueType, 
         class Pol1 = DefaultArgument, 
         class Pol2 = DefaultArgument>
class MyClass {
    typedef use_policies<Pol1, Pol2> policies;

    typedef KeyType key_type;
    typedef ValueType value_type;
    typedef typename policies::
      template apply_key_compare<KeyType>::type 
      key_compare;
    typedef typename policies::
      template apply_value_compare<ValueType>::type 
      value_compare;
};

ここで、使用するデフォルト引数を用意します。これには、提供するデフォルト引数の typedef があります。メンバー テンプレートは、キーと値の型によってパラメーター化されます。

struct VirtualRoot { 
  template<typename KeyType>
  struct apply_key_compare {
    typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> 
      type;
  };
  template<typename ValueType>
  struct apply_value_compare {
    typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType> 
      type;
  };
};

struct DefaultArgument : virtual VirtualRoot { };

template<typename T> struct KeyCompareIs : virtual VirtualRoot {
  template<typename KeyType>
  struct apply_key_compare {
    typedef T type;
  };
};

template<typename T> struct ValueCompareIs : virtual VirtualRoot {
  template<typename ValueType>
  struct apply_value_compare {
    typedef T type;
  };
};

これで、use_policiesすべてのテンプレート引数から派生します。の派生クラスがメンバーをベースから隠している場合、派生クラスのVirtualRootそのメンバーはベースのメンバーよりも支配的であり、継承ツリー内の他のパスによってベースクラスのメンバーに到達できる場合でも使用されます。

type のオブジェクトを作成することはないため、仮想継承の料金は発生しないことに注意してくださいuse_policies。仮想継承のみを使用して、支配規則を利用します。

template<typename B, int>
struct Inherit : B { };

template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };

同じクラスから複数回派生する可能性があるため、クラス テンプレートを使用しますInherit。同じクラスを直接 2 回継承することは禁止されています。ただし、間接的に継承することは許可されています。これをすべて次のように使用できるようになりました。

MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;
于 2009-08-28T23:48:57.997 に答える