7

ここで提起した問題に続いて、この質問をします。

ポイントは至ってシンプルです。この種の 2 つのクラスがあるとします。

template < class Derived >
class Base {
...
operator const Derived&() const {
    return static_cast< const Derived& >(*this);
  }
...
};

class Specialization : public Base<Specialization> {
...
};

次に、次のような型変換があるとします。

template < class T >
functionCall( const Base<T>& param) {
  const T & val(param);
  ...
}

問題は、この変換の標準準拠の動作はどうあるべきかということです。

と同じにする必要がありますか、const T & val(static_cast<const T &> (param) ) それともスタック オーバーフローまで再帰的に反復する必要がありますか? GNUg++でコンパイルした最初の動作と Intel でコンパイルした 2 番目の動作が得られたことに注意してくださいicpc

私はすでに標準 (static_cast のセクション 5.9 と変換のセクション 12.3) をのぞき見しようとしましたが、経験不足のため、答えを見つけることができませんでした。

これを手伝ってくれる時間を割いてくれた人に、前もって感謝します。

4

2 に答える 2

3

n3337の[expr.static.cast]を見てください(標準の後の最初の作業ドラフト):

2 /「cv1 B」タイプの左辺値(はクラスタイプ)は、「ポインタから」から「への有効な標準変換」の場合、から派生したクラス(10節)である「Bcv2への参照」タイプにキャストできます。 」へのポインタが存在します[...]DDBDB

4 /それ以外の場合、宣言が整形式であれば、いくつかの発明された一時変数[..]に対して、形式のaを使用しeて式を明示的に型に変換できます。Tstatic_caststatic_cast<T>(e)T t(e);t

したがって、gccの動作は正しいもの、つまり次の式であると解釈します。

static_cast<Derived const&>(*this)

再帰的に呼び出すべきではありませんoperator Derived const& () const

これは、ルールの順序を意味するElatherキーワードの存在から推測します。ルール2/は、ルールの前に試す必要があります4/

于 2012-03-22T10:28:34.753 に答える
0

暗黙的な変換演算子の使用はお勧めしません。C++11 ではexplicit、単一引数のコンストラクターだけでなく、変換演算子にもキーワードを追加できます。self()C++03 コードの場合、またはなどの明示的に名前が付けられた変換関数を使用できますdown_cast()

さらに、BaseCRTP、つまり静的ポリモーフィズムを有効にするためにクラスを使用しているようです。つまり、呼び出している特定のクラスをコンパイル時に知る必要があります。したがって、 CRTP インターフェイスを実装する場合を除いて、パブリック コードで参照Derivedを使用する必要はありません。const Base&

私のプロジェクトには、クラス テンプレートがありenable_crtpます。

#include <type_traits>
#include <boost/static_assert.hpp>

template
<
        typename Derived
>
class enable_crtp
{
public:
        const Derived& self() const
        {
                return down_cast(*this);
        }

        Derived& self()
        {
                return down_cast(*this);
        }

protected:
        // disable deletion of Derived* through Base* 
        // enable deletion of Base* through Derived*
        ~enable_crtp()
        {
                // no-op
        }

private:
        // typedefs
        typedef enable_crtp Base;

        // cast a Base& to a Derived& (i.e. "down" the class hierarchy)
        const Derived& down_cast(const Base& other) const
        {
              BOOST_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
              return static_cast<const Derived&>(other);
        }

        // cast a Base& to a Derived& (i.e. "down" the class hierarchy)
        Derived& down_cast(Base& other)
        {
        // write the non-const version in terms of the const version
        // Effective C++ 3rd ed., Item 3 (p. 24-25)
        return const_cast<Derived&>(down_cast(static_cast<const Base&>(other)));
        }
};

このクラスは、次のような CRTP 基本クラス ISomeClass からプライベートに派生します。

template<typename Impl>
class ISomeClass
:
    private enable_crtp<Impl>
{
public:
    // interface to be implemented by derived class Impl
    void fun1() const
    {
        self().do_fun1();
    }

    void fun2()
    {
        self().do_fun2()
    }

protected:
    ~ISomeClass()
    {}  
};

さまざまな派生クラスは、次のような独自の方法でこのインターフェイスを実装できます。

class SomeImpl
:
    public ISomeClass<SomeImpl>
{
public:
    // structors etc.

private:
    // implementation of interface ISomeClass

    friend class ISomeClass<SomeImpl>;

    void do_fun1() const
    {
        // whatever
    }

    void do_fun2() 
    {
        // whatever
    }

    // data representation
    // ...
};

の外部コード呼び出しfun1class SomeImpl、の適切な const または非 const バージョンに委譲され、self()down_castingclass enable_crtpの後に実装do_fun1が呼び出されます。適切なコンパイラを使用すると、すべての間接化を完全に最適化する必要があります。

注: および の保護されたデストラクタはISomeClass、ベース ポインタを介してオブジェクトenable_crtpを削除しようとするユーザーに対してコードを安全にします。SomeImpl*

于 2012-04-18T14:47:45.107 に答える