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 检测类中是否存在成员/成员函数。

(一个简单的解决方案是添加一个额外的默认参数——前提是您有启用 C++11 的编译器:

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

)

于 2012-07-19T18:15:42.860 回答