2016-09-20 17 views
1

derived<T>クラスの*thisがまだbase<T>タイプの理由は何ですか?* thisを返すメンバー関数を継承する

私はtypename Xがそれを処理すると思っていました。

これが醜い場合は、より良い方法はありますか?

未遂:

template <typename T> 
class Derived; 

template <typename T, typename X> 
class Base{ 
    public: 
     T val; 
     X f(void){ 
      return *this; 
     } 
}; 

template <typename T> 
class Derived: public Base<T, Derived<T> >{ 
}; 


int main(void){ 
    Derived<int> B; 
    Derived<int> C = B.f(); 
} 

がエラー:

test4.cpp(9): error: no suitable user-defined conversion from "Base<int, Derived<int>>" to "Derived<int>" exists 
       return *this; 
        ^
      detected during instantiation of "X Base<T, X>::f() [with T=int, X=Derived<int>]" at line 20 

compilation aborted for test4.cpp (code 2) 
+1

'f'は' Base'のメンバ関数なので '* this'は' Base'型です。 –

+1

_派生したクラスの* thisがまだ型のベースであるのはなぜですか? "__ static_cast < > '?? –

+0

あなたのアサーションは真実ではありません。問題の 'this 'は明らかに' Base'内で発生します。 –

答えて

1

まず、Baseを修正して、1つのテンプレートパラメータのみを受け入れるようにします。
これは、CRTPイディオムで示されている一般的な形式とまったく同じです。
実際には、すでに前者が含まれているとT, Derived<T>あなたが付着したいパターンである後者のために、このような場合にはテンプレートパラメータとして両方TDerived<T>を使用する理由はないように私には思える:

あなたがsysteを作っている、ここで

X<T> f(void) { 
    return *static_cast<X<T>*>(this); 
} 

注:@ Jarod42で述べたように

template<typename> 
class Base; 

template <typename T, template<typename> typename X> 
class Base<X<T>> { 
    // ... 
}; 

template <typename T> 
class Derived: public Base<Derived<T>>{ 
    // .... 
}; 

は、その後、あなたは下からプロモーションを使用することができますおそらくそれはあなたが望むものではありません。

あなたのために優れている1
template <typename T> 
class Base { 
    T val; 

public: 
    virtual const Base<T>& f(void) const { 
     return *this; 
    } 
}; 

template <typename T> 
class Derived: public Base<T> { 
public: 
    virtual const Derived<T>& f(void) const { 
     return *this; 
    } 
}; 

int main(void) { 
    Derived<int> B; 
    Derived<int> C = B.f(); 
} 

は、ほとんどが実際の問題に依存します:

別のオプションは、(それが最小限の、実施例を以下の)ビットにアーキテクチャを変更し、共変戻り値の型を使用することです。

3

あなたは意気消沈して操作を行うことがあります。

X f(){ return static_cast<X&>(*this);} 
2

あなたは

X f(void){ 
    return *this; 
} 
を持っています

この関数では、タイプ*thisは引き続き基本クラス型です。基本タイプからXへの自動変換はありません。

Xはその時点で何でもかまいません。必ずしもDerived<T>である必要はありません。

私が使用することができます。

template <typename T> 
class Derived2 : public Base<T, double> 
{ 
}; 

はどのように基底クラスはそれに対処することになっていますか?

f()で使用されているアプローチは設計上の欠陥のようです。

更新

template <typename T> 
class Derived : public Base<T, Derived<T>> 
{ 
}; 

次にフォームを持つことが保証されてDerived場合は、使用することができます。

X& f(void){ 
    return static_cast<X&>(*this); 
} 

は私がXから戻り値の型を変更することに注意してくださいX&。これは、関数を呼び出すたびにコピーを作成するコストを回避します。

+0

複数の派生クラスを作成する方法は、すべて自分自身を返す関数を持っていますか?そのような基本クラスの関数を定義することは不可能ですか?そのデザインの欠陥を修正するには? – rxu

+0

私は、すべての派生クラスに関数をコピーして貼り付けても安全だと思います...もっと良い方法はありますか? – rxu

+0

@ rxuの場合、解決策は「それ以降のオブジェクトで何をしたいですか?」という質問に対する答えにある可能性があります。 –

2

コンパイラがclass Base<int, Derived<int>>を見ると、実際にはDerived<int>が継承されているとは考えられません。 1つはclass Other : public Base<T, Derived<T>>{}で、class Base<int, Derived<int>>からDerived<int>への変換は正しくないため、自動変換は許可されません。

2番目のテンプレートパラメータが、基底を継承する派生型(class Otherに違反している)でなければならないというルールを作成した場合は、型システムをキャストでバイパスできますが、ルールに違反していないことを確認します。

関連する問題