2

The question How does `void_t` work shows an example of SFINAE using void_t on a class data member T::member. However, it doesn't work if member is a function. Why is that the case ? It works if I change the code from decltype( T::member ) to decltype( T().member() ).

#include <iostream>

using namespace std;

template< class ... > using void_t = void;

template< class , class = void >
struct has_member : std::false_type
{ };

template< class T >
struct has_member< T , void_t< decltype( T::member ) > > : std::true_type
{ }; 

struct  A {
    void member();
};


int main()
{
    static_assert( has_member< A >::value , "A" ); // assertion fails

    return 0;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
sdp
  • 97
  • 1
  • 4
  • If you change it to `decltype(T().member())` you get the decl type of the return value of `member`, don't you? – Scheff's Cat Jul 19 '21 at 07:42
  • 1
    `decltype(&T::member)` for method function should work too, `T::non_static_method_function` is invalid. – Jarod42 Jul 19 '21 at 07:47
  • `decltype(T().member())` also need default constructible `T`, `decltype(std::declval().member())` is better. – Jarod42 Jul 19 '21 at 07:47

1 Answers1

5

decltype( T::member ) doesn't work because T::member is not a valid expression expected by decltype when member refers to a non-static member function.

You can change it to decltype( &T::member ) instead. &T::member returns pointer to member, it works with both member functions and data members, static or non-static.

BTW: Why is “using namespace std;” considered bad practice?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405