2

次のような Serializer クラスがあります。

class Serializer
{
public:
    // Func 1 (default)
    template <class T>
    void Serialize(T* pValue)
    {
        SerializeInternal(reinterpret_cast<char*>(pValue), sizeof(*pValue));
    }

    // Func 2 (specialization)
    template <> 
    void Serialize<Serializable>(Serializable* pSerializable)
    {
        pSerializable->Serialize(*this);
    }

protected:

    // Implemented by input and output serializers
    virtual void SerializeInternal(char* pData, size_t size) = 0;
};

今私の問題は、Serializable インターフェイスを継承するクラスがある場合、それらを Func 2 で処理したい場合でも、常に Func 1 で処理されることです (ポインターまたは参照はどちらも同じように動作します)。次のように明確に指定しない限り、C++ は Serializable インターフェイスが継承されていることを認識しないようです。

SerializableClass sc; // Inherits Serializable
InputSerializer s; // Inherits Serializer

s.Serialize(&sc); // Func 1 is called >:(
s.Serialize<Serializable>(&sc); // Func 2 is called

もちろん、どこかに追加するのを忘れるとすぐに<Serializable>、プログラムはバグアウトします。これはかなり面倒です。

これを回避する方法はありますか?

4

3 に答える 3

1

明確に指定しない限り、C++はSerializableインターフェースが継承されていることを認識しないようです

これは本当です。クラスがあれば

class SerializableClass : public Serializable

パラメーターを推測するときに、 only SerializableClass、 notSerializableが考慮されTます。

2 つの関数を作成する必要があり、1 つは任意のポインターを受け取り、もう 1 つは Serializable から派生したものへのポインターを受け取る場合、2 つのオーバーロードを作成し、可能であれば SFINAE を使用して狭い方を選択できます。

template <class T>
typename boost::enable_if_c<!boost::is_base_of<Serializable, T>::value, void>::type foo(T*) { ... }

template <class T>
typename boost::enable_if<boost::is_base_of<Serializable, T>, void>::type foo(T*) { ... }

ブーストを使用したくない場合は、これに似た必要な機能を実装できます。

于 2010-12-08T16:56:10.043 に答える
0

どのように機能するかを説明するリンクを見つけましたboost::is_base_of: How does `is_base_of` work?

どうやら彼らはそれを機能させるためにかなり派手なテンプレートフーマジックを使用しているようです. 同様の関数を自分で「簡単に」書くことができます。

自分で解決するほど賢くない場合は、プロを見てください ;)

于 2010-12-08T18:05:38.883 に答える
0

テンプレートの特殊化の代わりにオーバーロードを使用してください!

于 2010-12-08T16:47:34.267 に答える