6

SFINAE を有利に使用する方法を学んでいます。オブジェクト内の関数の存在に基づいて関数の実装を選択するために使用しようとしてserialize()います。

これは、型が serialize() 関数を定義しているかどうかを判断するために使用するコードです。

template <typename T>
class HasSerialize {
    private:
        typedef char yes[1];
        typedef char no[2];

        template <typename C> static yes& test(char[sizeof(&C::serialize)]) ;
        template <typename C> static no& test(...);
    public:
        static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

ただし、GCC と Clang では正反対の結果が得られるようです。次のコードを想定します。

template<bool T>
class NVPtypeSerializer {
    public:
        template<typename C>
        static xmlChar* serialize(C value) {
            // serize() is not available
        }
};

template<>
struct NVPtypeSerializer<true> {
    public:
        template<typename T>
        static xmlChar* serialize(T value) {
            return value.serialize();
        }
};

これは次のように呼び出されます:

foo = NVPtypeSerializer<HasSerialize<Bar>::value >::serialize(value);

クラスBarに機能がないserialize()場合。このコードは Clang 3.1 では正常にコンパイルされますが、GCC 4.7.1 では次のエラーが発生します。

error: ‘class Bar’ has no member named ‘serialize’

に変更するstruct NVPtypeSerializer<true>struct NVPtypeSerializer<false>、GCC でコンパイルできますが、Clang で次のエラーが発生します。

error: no member named 'serialize' in 'Bar'

問題はどこだ?それは私のコードにありますか?コードをできるだけ移植できるようにしたいと思います。

4

1 に答える 1

3

これは本当にコードtest(char[sizeof(&C::serialize)])ですか?配列を取る関数の宣言は、実際にはポインターを取る関数を宣言することに注意してください。

template <typename C> static yes& test(char[sizeof(&C::serialize)]) ;

それは実際には次のことを意味します。

template <typename C> static yes& test( char* );

ちなみに、これはあなたの呼び出しtest<C>(0)をコンパイルさせるものです。関数が存在するかどうかを検出する適切な方法ではないと思います。SFINAE を使用してクラスにメンバー/メンバー関数が存在するかどうかを検出する方法については、Google を参照してください。

(簡単な解決策は、デフォルトの引数を追加することです -- C++11 対応のコンパイラがある場合:

template <typename C, std::size_t = sizeof(&C::serialize)> 
static yes& test(int) ;

)

于 2012-07-19T18:15:42.860 に答える