2010-12-18 5 views
12

派生クラスをテンプレートクラスの子孫にしたい。そのクラスは子孫のメンバーに依存します。 は、一言で言えば、私はこのコードをコンパイルする:派生クラスのtypedefのベースへの使用

struct IBootParams 
{ 
    virtual bool GetImmediate() = 0; 
}; 

template <class T> 
struct TBootBootParams 
{ 
    typename T::TransType transferType; 

    typename T::UseAbort_ useAbort; 

    bool GetImmediate() 
    { 
     if (transferType == T::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams : public TBootBootParams<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=0, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     char  someMember;    
     int   otherMember;   
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootAltBootParams : public TBootBootParams<BootAltBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 
+0

それでエラーは何ですか? – ybungalobill

+2

なぜIBootParamsを宣言しましたか?あなたが近くだったので –

答えて

10

このようにすることはできません。コンパイラがTBootBootParams<BootBootParams>をインスタンス化すると、BootBootParamsの定義全体を完全に読み取ることができないため、TBootBootParamsの定義内からメンバーにアクセスすることはできません(TBootBootParamsのメンバー関数は後でインスタンス化されるため例外です)。

通常のソリューションは、特性クラスを持つことです。

template<class T> struct TBootBootParams_traits; 

template <class T> 
struct TBootBootParams 
{ 
    typename TBootBootParams_traits<T>::TransType transferType; 

    typename TBootBootParams_traits<T>::UseAbort_ useAbort; 

    bool GetImmediate() 
    { 
     if (transferType == TBootBootParams_traits<T>::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams; 
template<> struct TBootBootParams_traits<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    }; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootBootParams : 
    public TBootBootParams<BootBootParams>, 
    public TBootBootParams_traits<BootBootParams> 
{ 
    UseAbort_ useAbort; 
}; 
+0

これは私が思うより良いハックです。ビットクリーナー。 – Omnifarious

+0

素晴らしいですね。なぜ 'template <> struct TBootBootParams_traits'宣言の前方宣言が' <> '内に型パラメータを持たないのか分かりません。 –

+1

@ Sergey:それは特殊化のためです。 @All + @Omnifarious:いくつかのパラメータをいくつかのテンプレートに渡す標準的な方法です。例えば。 STLは、イテレータ(iterator_traits)にこれを使用します。 – ybungalobill

4

これはそれはハックのビットではありません働くことができる方法はありません。だからここにハックのビットで私の試みです:仕事へのこのアプローチのために

struct IBootParams 
{ 
    virtual bool GetImmediate() = 0; 
}; 

template <class T> 
struct TBootBootParams : public IBootParams 
{ 
    typename T::TransType transferType; 

    typename T::UseAbort_ useAbort; 

    virtual bool GetImmediate() 
    { 
     if (transferType == T::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams_types 
{ 
    enum SomeEnum 
    { 
     e1=0, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag; 

     char  someMember; 
     int   otherMember; 
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootBootParams : public BootBootParams_types, 
         public TBootBootParams<BootBootParams_types> 
{ 
}; 

struct BootAltBootParams_types 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag; 

     long long  someMember; 
     long long  otherMember; 
    } useAbort; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootAltBootParams : public BootAltBootParams_types, 
          public TBootBootParams<BootAltBootParams_types> 
{ 
}; 

int main(int argc, const char * argv[]) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 
+1

+1: – ybungalobill

+1

ありがとう。面白い! – Romeno

0

、あなたは親クラスのメンバーとしてテンプレートクラスのオブジェクトを含める必要があります。

2

これは、あなたがやりたいのか? It compiles.

struct IBootParams 
{ 
    virtual bool GetImmediate() = 0; 
}; 

template <class T> 
struct TBootBootParams 
{ 
    bool GetImmediate() 
    { 
     if (static_cast<T*>(this)->transferType == T::e1) 
     { 
      return static_cast<T*>(this)->useAbort.someFlag; 
     } 

     return false; 
    } 

}; 

struct BootBootParams : public TBootBootParams<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=0, 
     e2, 
     e3 
    } transferType; 

    struct UseAbort 
    { 
     bool  someFlag;   

     char  someMember;    
     int   otherMember;   
    } useAbort; 
}; 

struct BootAltBootParams : public TBootBootParams<BootAltBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    } transferType; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    } useAbort; 
}; 

int main(void) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 
+0

Wow。私は本当にコンパイルすることに感心しています。それはコンパイルされるはずですか?それが実際に機能しているという理由だけで、それが想定されているわけではありません。 :-) – Omnifarious

+0

ところで、gcc 4.5でもコンパイルされます。 – Omnifarious

+0

@Omnifarious:はい、これはコンパイルする必要があります、それは簡単なCRTPです。問題の原因となった基本クラスのメンバーを取り除きました。データ型は派生型によって決まり、派生型で宣言でき、基本クラスはテンプレートパラメータを利用するだけで問題なくアクセスできます。 –

1

私は自分自身のニーズをカウントybungalobillのソリューションにほとんど変化を試してみました。そして、私は要約すると

template<class T> 
struct TBootBootParams_traits; 

template <class T> 
struct TBootBootParams 
{ 
    typedef TBootBootParams_traits<T> Traits; 

    typename Traits::TransType transferType; 
    typename Traits::UseAbort_ useAbort; 

    bool GetImmediate() 
    { 
     if (transferType == TBootBootParams_traits<T>::e1) 
     { 
      return useAbort.someFlag; 
     } 

     return false; 
    } 
}; 

struct BootBootParams; 
struct BootAltBootParams; 

template<> 
struct TBootBootParams_traits<BootBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     long long  someMember;    
     long long  otherMember;   
    }; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

template<> 
struct TBootBootParams_traits<BootAltBootParams> 
{ 
    enum SomeEnum 
    { 
     e1=5, 
     e2, 
     e3 
    }; 

    struct UseAbort 
    { 
     bool  someFlag;   

     int someMember;    
     float otherMember;   
    }; 

    typedef SomeEnum TransType; 
    typedef UseAbort UseAbort_; 
}; 

struct BootBootParams : 
    public TBootBootParams<BootBootParams> 
{ 

}; 

struct BootAltBootParams : 
    public TBootBootParams<BootAltBootParams> 
{ 

}; 

int main(void) 
{ 
    BootBootParams bp; 
    BootAltBootParams bpa; 

    bool f = bp.GetImmediate(); 
    f = bpa.GetImmediate(); 
} 

を得たもの、これは..私はそこにすべてのタイプのデータを置くこのクラスの別のクラスの持っている必要がありますオプションとしてテンプレートクラスを使用します。これは私が必要としたものです。オプションにもう一度感謝します!

関連する問題