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,
C
is considered to have the memberFoo
sinceA
has implementedFoo
,C
is considered to have the free functionFoo
implemented sinceFoo
acceptconst 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.