12

Curiously Recurring Template Pattern (CRTP) を使用して、追加の型パラメーターを提供しようとしています。

template <typename Subclass, typename Int, typename Float>
class Base {
    Int *i;
    Float *f;
};
...

class A : public Base<A, double, int> {
};

これはおそらくバグであり、より適切なスーパークラスがありますBase<A, double, int>-- ただし、この引数の順序の不一致はそれほど明白ではありません。このバグは、typedef 内のパラメーターの意味に name を使用できれば、簡単に確認できます。

template <typename Subclass>
class Base {
    typename Subclass::Int_t *i;  // error: invalid use of incomplete type ‘class A’
    typename Subclass::Float_t *f;
};

class A : public Base<A> {
    typedef double Int_t;         // error: forward declaration of ‘class A’
    typedef int Double_t;
};

ただし、これは gcc 4.4 ではコンパイルされません。報告されたエラーは上記のコメントとして示されています。その理由は、A を作成する前に Base テンプレートをインスタンス化する必要があるためだと思いますが、これには A を知る必要があります。

CRTP の使用中に「名前付き」テンプレート パラメータを渡す良い方法はありますか?

4

3 に答える 3

23

特性クラスを使用できます。

// Must be specialized for any type used as TDerived in Base<TDerived>.
// Each specialization must provide an IntType typedef and a FloatType typedef.
template <typename TDerived>
struct BaseTraits;

template <typename TDerived>
struct Base 
{
    typename BaseTraits<TDerived>::IntType *i;
    typename BaseTraits<TDerived>::FloatType *f;
};

struct Derived;

template <>
struct BaseTraits<Derived> 
{
    typedef int IntType;
    typedef float FloatType;
};

struct Derived : Base<Derived> 
{
};
于 2011-04-15T17:29:23.507 に答える
10

@Jamesの答えは明らかに正しいですが、ユーザーが正しいtypedefを提供しないと、それでも問題が発生する可能性があります。

コンパイル時のチェック機能を使用して、使用されている型が正しいことを「アサート」することができます。使用する C++ のバージョンによっては、Boost を使用する必要がある場合があります。

C++0x では、これは次の組み合わせで行われます。

  • static_assert: コンパイル時のチェックのための新しい機能で、メッセージを指定できます
  • またはtype_traitsのようないくつかの述語を提供するヘッダーstd::is_integralstd::is_floating_point

例:

template <typename TDerived>
struct Base
{
  typedef typename BaseTraits<TDerived>::IntType IntType;
  typedef typename BaseTraits<TDerived>::FloatType FloatType;

  static_assert(std::is_integral<IntType>::value,
    "BaseTraits<TDerived>::IntType should have been an integral type");
  static_assert(std::is_floating_point<FloatType>::value,
    "BaseTraits<TDerived>::FloatType should have been a floating point type");

};

これは、ランタイムの世界における典型的な防御的プログラミングのイディオムに非常に似ています。

于 2011-04-15T18:15:50.107 に答える