KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
has_member.hpp File Reference

Macros for generating concept-like type traits to check for member functions of objects. More...

#include <type_traits>
Include dependency graph for has_member.hpp:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define KAMPING_MAKE_HAS_MEMBER(Member)
 Macro for generating has_member_xxx and has_member_xxx_v templates. They return true if the type given as template parameter has a member (template) function provided name.
 

Detailed Description

Macros for generating concept-like type traits to check for member functions of objects.

Macro Definition Documentation

◆ KAMPING_MAKE_HAS_MEMBER

#define KAMPING_MAKE_HAS_MEMBER ( Member)
Value:
template <typename Type, typename... MemberArgs> \
class has_member_##Member { \
template < \
typename C, \
typename = std::void_t<decltype(std::declval<C>().Member(std::declval<MemberArgs>()...))>> \
static auto test(int) -> std::true_type; \
template <typename C> \
static auto test(long) -> std::false_type; \
template < \
typename C, \
typename... TemplateParams, \
typename = std::void_t< \
decltype(std::declval<C>().template Member<TemplateParams...>(std::declval<MemberArgs>()...))>> \
static auto test_with_template_params(int) -> std::true_type; \
template <typename C, typename... TemplateParams> \
static auto test_with_template_params(long) -> std::false_type; \
\
public: \
static constexpr bool value = decltype(test<Type>(0))::value; \
\
template <typename... TemplateParams> \
static constexpr bool value_with_template_params = \
decltype(test_with_template_params<Type, TemplateParams...>(0))::value; \
}; \
\
template <typename Type, typename... MemberArgs> \
[[maybe_unused]] static constexpr bool has_member_##Member##_v = has_member_##Member<Type, MemberArgs...>::value;

Macro for generating has_member_xxx and has_member_xxx_v templates. They return true if the type given as template parameter has a member (template) function provided name.

If the function has no template parameters or they can be auto-deduced, use has_member_xxx::value or has_member_xxx_v, if not use has_member_xxx::value_with_template_params<...>.

If the member function takes arguments, pass their types as additional template parameters to has_member_xxx.

See the examples for details.

Example:

// Add templates has_member_bar and has_member_bar_v
// Add templates has_member_baz and has_member_baz_v
// Add templates has_member_fizz and has_member_fizz_v
struct Foo {
int bar();
int baz(char);
template<typename T>
int fizz(T);
};
// check if Foo.bar() is callable
static_assert(has_member_bar_v<Foo>)
// check if Foo.bar(char) is callable
static_assert(!has_member_bar_v<Foo, char>)
// check if Foo.baz(char) is callable
static_assert(has_member_baz_v<Foo, char>)
// check if Foo.baz() is callable
static_assert(!has_member_baz_v<Foo>)
// check if Foo.fizz(int) is callable
static_assert(has_member_fizz_v<Foo, int>)
// check if Foo.fizz<int>(int) is callable
static_assert(has_member_fizz<Foo, int>::value_with_template_params<int>)
// check if Foo.fizz<int, double>() is callable
static_assert(!has_member_fizz<Foo>::value_with_template_params<int, double>)
#define KAMPING_MAKE_HAS_MEMBER(Member)
Macro for generating has_member_xxx and has_member_xxx_v templates. They return true if the type give...
Definition has_member.hpp:91

Explanation:

  • To obtain value, the static member function test is instantiated using the given type Type.
  • Using declval, we get an instance of Type and try to call the expected member function with instances of the passed MemberArgs.
    • Optionally, test_with_template_params also instantiates the functions template parameters with the passed types.
  • If that member does not exist, we can not obtain the decltype, and cannot instantiate std::void_t<...>, which fails to initialize the whole function test(int).
  • Then, the next best instantiation is test(long), which returns std::false_type.
  • If we find the requested member, we get std::true_type.
  • test has int and long overloads to resolve ambiguity. Passing 0 to test ensure that we first try to instantiate the true variant.