Search code examples
c++templatesvisual-studio-2013sfinaedecltype

error with decltype template with msvc2013


I'm trying to use the following construct to check for the existence of a member function based on this answer that I previously got:

template <typename T, class = double>
struct has_a : std::false_type {};

template <typename T>
struct has_a<T, decltype(std::declval<T>().a())> : std::true_type {};

This works fine with gcc 4.9.2, but fails to compile with msvc2013:

error C2228: left of '.a' must have class/struct/union type is 'add_rvalue_reference<_Ty>::type'

It seems(?) like this is a compiler bug, since declval is specifically supposed to work within an unevaluated decltype expression (see here). Is there a known workaround?


Solution

  • MSVC 2013's trailing return type parser appears to be more complete than the expression SFINAE system, and if the checker is refactored the following way (following T.C's suggestion), it works as expected on both msvc2013 and gcc 4.9.2:

    template <typename T>
    struct has_a_impl
    {
        template<typename U>
        static auto test(U* p) -> decltype(p->a()); // checks function existence
        template<typename U>
        static auto test(...) -> std::false_type;
    
        using type = typename std::is_floating_point<decltype(test<T>(0))>::type; // checks return type is some kind of floating point
    };
    
    template <typename T>
    struct has_a : has_a_impl<T>::type {};
    

    An added benefit of this syntax is the return type check can use any of the type_traits, so you don't have to check for a single type of return value (e.g. double).