1

最近、私はテンプレートをいじっていて、次の問題に遭遇しました。次のような CRTP パターンを実装しています。

template<typename derived_t>
struct protocol_object
{
    ...
};

struct data_object : public protocol_object<data_object>
{
    ...
};

class protocol_object非 CRTP タイプを受け入れながら、メンバー テンプレート関数内の のインスタンスを一致させたいと思います。

struct consumer_impl
{
    template<typename derived_t>
    void match(protocol_object<derived_t> &value)
    {
       std::cout << "protocol_class";
    };

    template<typename T>
    void match(T &value)
    {
       std::cout << "any other type";
    };
}

残念ながら、これまでに呼び出されたのは 2 番目のバージョンだけです。明らかmatch(protocol_object<derived_t> &value)に、より一般的な形式を支持して考慮または拒否されていませんmatch(T &value)

data_object object;
double value;
consumer_impl consumer;

consumer.match(value);  // yields "any other type" OK
consumer.match(object); // also yields "any other type" but want "protocol_class"

これから抜け出す方法はありますか?

ヒントをありがとう。アルネ

4

3 に答える 3

2

これはCRTPとは関係ありません。これは、次の一般的なケースです。

  • すべての派生クラスが特定の特殊化を使用するように、テンプレート関数を設計します。

問題は、T& valueが完全に一致しているのDerived&に対し、Base&は不正確に一致していることです。したがって、一般的な形式をより悪い一致にします。

struct conversion_required { conversion_required(int) {} };

template<typename derived_t>
void match_impl(protocol_object<derived_t> &value, int)
{
   std::cout << "protocol_class";
};

template<typename T>
void match_impl(T &value, conversion_required)
{
   std::cout << "any other type";
};

template<typename T>
void match(T& value)
{
    return match_impl(value, 0);
}

現在、アップキャストを必要とする特殊化は、ユーザー定義の変換を必要とする一般的なテンプレートよりもよく一致しています。

于 2011-10-23T23:53:37.917 に答える
0

2 番目の関数は変換が不要なため、より適しています。一方、最初の関数は派生から基底への変換が必要です。

これを克服するためにブーストを使用できます。

template <class T>
void
match (typename boost::enable_if_c
             <boost::is_base_of<protocol_object<T>,T>::value, T>::type& t)
{
    std::cout << "protocol_class";
}

template <class T>
void
match (typename boost::disable_if_c
             <boost::is_base_of<protocol_object<T>,T>::value, T>::type& t)
{
    std::cout << "any other type";
}

Tこれは、から派生したすべてのクラスで機能しますが、それ自体protocol_object<T>では機能しませんprotocol_object<T>。それに別のオーバーロードを追加するか (基本的に、最初のmatch関数を再利用します)、条件がenable_if一致するように変更することprotocol_object<T>もできます。

于 2011-10-24T00:25:06.730 に答える
0

コンパイル時のコンパイラの決定であるため、オーバーロードの解決はstatic typeに基づいて実行されます。これを試して:

consumer.match(static_cast<protocol_object<data_object>&>(object));
于 2011-10-23T23:51:56.080 に答える