Home > front end >  How to check if a member function or free function is for the exact given type(not any of its base)?
How to check if a member function or free function is for the exact given type(not any of its base)?

Time:11-14

A way to check if a member function/free function can be invoked on an object would be to:

#include <type_traits>
#include <utility>

template <class T, class = void>
struct HasMember : std::false_type {};
template <class T>
struct HasMember<T, std::void_t<decltype(std::declval<T>().Foo())>> : std::true_type {};

template <class T, class = void>
struct HasFreeFoo : std::false_type {};
template <class T>
struct HasFreeFoo<T, std::void_t<decltype(Foo(std::declval<T>()))>> : std::true_type {};

struct A { void Foo() {} }; 
struct B : A {};
struct C : B {};
                                          
void Foo(const A &) {}

int main() {
  static_assert(HasMember<C>::value, "");
  static_assert(HasFreeFoo<C>::value, "");
}

But as what the example demonstrates,

  1. C is considered to have the member Foo since A has implemented Foo,
  2. C is considered to have the free function Foo implemented since Foo accept const A &.

What I want to achieve is to have HasMember<A>::value == true && HasMember<C>::value == false. HasFreeFoo<A>::value == true && HasFreeFoo<C>::value == false. Any help is welcome, thanks.

Background: I am implementing a ser/des tool, user can choose to either implement a member function or a free function to specify how should a type get ser/des. And I need to check if such member function / free function are implemented (not inherited from its base) exactly for the given type .

CodePudding user response:

The implementation of HasMember and HasFreeFoo is reasonable since C can indeed obtain Foo() through inheritance. What you need is to implement another trait to choose whether to invoke through the member function or the free function. For example:

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

template <class T>
struct UseMemberFoo<T, std::enable_if_t<HasMember<T>::value && !HasFreeFoo<T>::value>>
 : std::true_type { };

template<class T>
void Foo(const T&) = delete;

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

template <class T>
struct UseFreeFoo<T, std::enable_if_t<HasMember<T>::value && HasFreeFoo<T>::value>>
 : std::true_type { };

When T only has member Foo(), then invoke it through the member function. When the user inherits the base class which has member Foo() and provides the free function for the derived class, then invoke it through the free function.

Demo.

  • Related