3

私のコードの簡略化されたバージョンは次のようになります。

template <class T>
struct Base
{
    void SayHello( T* aDerived )
    {
    }

    void SaySomething()
    {
        SayHello( this ); // This is where the error happens
    }
};

struct Derived : public Base< Derived >
{
};

int main(int argc, const char * argv[])
{
    Derived iDerived;
    iDerived.SaySomething();
}

SayHello( this )そして、次のエラーメッセージが表示された行ではコンパイルされません。

Cannot initialize a parameter of type 'Derived *'
with an rvalue of type 'Base<Derived> *'

これで、コンパイラがこれについて文句を言うのは理にかなっていますが、私には少しばかげているように見えますが、この行を削除しても文句はありません。

iDerived.SaySomething();

とにかく、この問題は、次のように明示的な型キャストを行うことで解決できます。

SayHello( (T*)this );

実際のコードはこれらのタイプキャストの多くで終わるということです。Baseテンプレートクラスに自動的にタイプキャストできるようにするものに含めるのが妥当なようです(T)。

それはoperator=私が求めているのですか?誰かがこれがどのように行われるかについてのコードサンプルを提供できますか?この質問は、私が次のようなことができることを示唆しています。

キャストは常にとの間thisですT*

operator T*()
{
    return (T*)this;
}

しかし、エラーは残ります。

4

2 に答える 2

3

少しばかげているように見えますが、この行を削除しても文句はありません[...]

いいえ、それは愚かなことではありません、それはテンプレートがどのように機能するかです。クラステンプレートのメンバー関数は、呼び出さないとインスタンス化されません。したがって、インスタンス化中に生成されるコンパイルエラーは表示されません。

この問題は、次のように明示的な型キャストを行うことで解決できます[...]

私は好むでしょうstatic_cast<>

SayHello( static_cast<T*>(this) );

関数がthis受け取るポインターは型ですが、(設計上)ポイントされているオブジェクトが実際には型であることを知っています。したがって、静的キャストを実行しても安全です。SaySomething()Base<Derived>Derived

テンプレートクラス(T)に自動的に型キャストできるものをBaseに含めるのは合理的だと思います。

この場合、ポインタを何度もキャストしても問題はありません。それが、CRTP(使用しているデザインパターン)が強制することです。気になる場合get_this()は、キャストを実行する関数を定義するだけです。

template <class T>
struct Base
{
    void SayHello( T* aDerived )
    {
    }

    void SaySomething()
    {
        SayHello( get_this() );
    }

private:

    // Version returning a non-const pointer
    T* get_this() { return static_cast<T*>(this); }

    // Version returning a const pointer
    T const* get_this() const { return static_cast<T const*>(this); }

};
于 2013-03-04T23:56:18.790 に答える
3

this派生型にダウンキャストを返すヘルパー関数を追加できます

template <class T>
struct Base
{
    void SayHello( T* aDerived )
    {
    }

    void SaySomething()
    {
        SayHello( derived_this() );
    }

private:
    T* derived_this()
    {
        return static_cast<T*>(this);
    }

constオーバーロードが必要な場合もあります。

    const T* derived_this() const
    {
        return static_cast<const T*>(this);
    }

暗黙の変換演算子を追加することもできますが、お勧めしません。

    operator T*() { return static_cast<T*>(this); }

derived_this()暗黙の変換は型システムを弱め、バグの原因となる可能性があります。などの明示的な関数はより明確で安全だと思います。

于 2013-03-05T00:06:18.017 に答える