1

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?

Community
  • 1
  • 1
Nicolas Holthaus
  • 7,763
  • 4
  • 42
  • 97
  • This relies on [expression SFINAE](http://stackoverflow.com/questions/12654067/what-is-expression-sfinae#12654277), but MSVC2013 [doesn't support it](https://msdn.microsoft.com/en-us/library/hh567368.aspx) (although I understand that they have some expression SFINAE features ready for the next version). – TartanLlama Jan 04 '16 at 16:06
  • @TartanLlama that's what I was worried about. Is there a similar idiom that doesn't break visual studio? – Nicolas Holthaus Jan 04 '16 at 16:10
  • @NicolasHolthaus [try this](http://rextester.com/BMCKE70673) – Piotr Skotnicki Jan 04 '16 at 16:16
  • 2
    Have you look at the different "check-if-class-has-function" as [check-if-class-has-function-with-signature](http://stackoverflow.com/questions/24975147/check-if-class-has-function-with-signature/24976592#24976592). there are variants which should work also for c++03 – Jarod42 Jan 04 '16 at 16:19
  • As far as I can tell, MSVC2013 seems to have some support for expression SFINAE in function template return types (they use it in their `allocator_traits` and `is_assignable`). Can you try [this](http://coliru.stacked-crooked.com/a/d2192109aa09f933)? – T.C. Jan 04 '16 at 16:37
  • @T.C. thanks, I was reading the same thing, and your sample helped me get to the answer. The actual solution is a tad lass verbose. – Nicolas Holthaus Jan 04 '16 at 18:27

1 Answers1

1

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).

Nicolas Holthaus
  • 7,763
  • 4
  • 42
  • 97