Using SFINAE gives different results on GCC and Clang

邮差的信 提交于 2019-12-10 13:29:46

问题


I'm learning how to use SFINAE to my advantage. I'm trying to use it to select the function implementation based on existence of a serialize() function in an object.

This is the code I use to determine, if the type defines the serialize() function:

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);
};

However, it seems to give exactly oposite results on GCC and on Clang. Assume the following code:

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();
        }
};

Which is called like this:

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

Where the class Bar doesn't have the serialize() function. This code compiles fine under Clang 3.1, however on GCC 4.7.1 I get the following errors:

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

If I change the struct NVPtypeSerializer<true> to struct NVPtypeSerializer<false> it can be compiled on GCC, but Clang gives the following error:

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

Where is the problem? Is it in my code? I'd like to have the code portable as much as possible.


回答1:


Is this really the code test(char[sizeof(&C::serialize)])? Note that a declaration of a function that takes an array actually declares a function that takes a pointer:

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

That actually means:

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

Which incidentally is what makes your call test<C>(0) compile. I don't think that is the proper way of detecting whether the function exists or not. Google on how to detect whether a member/member function exists in a class using SFINAE.

(A simple solution would be adding an extra defaulted argument --provided that you have a C++11 enabled compiler:

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

)



来源:https://stackoverflow.com/questions/11566564/using-sfinae-gives-different-results-on-gcc-and-clang

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!