KaMPIng
0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
has_member.hpp
Go to the documentation of this file.
1
// This file is part of KaMPIng.
2
//
3
// Copyright 2022 The KaMPIng Authors
4
//
5
// KaMPIng is free software : you can redistribute it and/or modify it under the
6
// terms of the GNU Lesser General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option) any
8
// later version. KaMPIng is distributed in the hope that it will be useful, but
9
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11
// for more details.
12
//
13
// You should have received a copy of the GNU Lesser General Public License
14
// along with KaMPIng. If not, see <https://www.gnu.org/licenses/>.
15
16
/// @file
17
/// @brief Macros for generating concept-like type traits to check for member functions of objects.
18
19
#pragma once
20
21
#include <type_traits>
22
23
/// @brief Macro for generating has_member_xxx and has_member_xxx_v templates.
24
/// They return true if the type given as template parameter has a member
25
/// (template) function provided name.
26
///
27
/// If the function has no template parameters or they can be auto-deduced, use
28
/// \c has_member_xxx::value or \c has_member_xxx_v, if not use \c
29
/// has_member_xxx::value_with_template_params<...>.
30
///
31
/// If the member function takes arguments, pass their types as additional
32
/// template parameters to \c has_member_xxx.
33
///
34
/// See the examples for details.
35
///
36
/// Example:
37
/// \code
38
/// // Add templates has_member_bar and has_member_bar_v
39
/// KAMPING_MAKE_HAS_MEMBER(bar)
40
///
41
/// // Add templates has_member_baz and has_member_baz_v
42
/// KAMPING_MAKE_HAS_MEMBER(baz)
43
///
44
/// // Add templates has_member_fizz and has_member_fizz_v
45
/// KAMPING_MAKE_HAS_MEMBER(fizz)
46
///
47
/// struct Foo {
48
/// int bar();
49
/// int baz(char);
50
/// template<typename T>
51
/// int fizz(T);
52
/// };
53
///
54
/// // check if Foo.bar() is callable
55
/// static_assert(has_member_bar_v<Foo>)
56
///
57
/// // check if Foo.bar(char) is callable
58
/// static_assert(!has_member_bar_v<Foo, char>)
59
///
60
/// // check if Foo.baz(char) is callable
61
/// static_assert(has_member_baz_v<Foo, char>)
62
///
63
/// // check if Foo.baz() is callable
64
/// static_assert(!has_member_baz_v<Foo>)
65
///
66
/// // check if Foo.fizz(int) is callable
67
/// static_assert(has_member_fizz_v<Foo, int>)
68
///
69
/// // check if Foo.fizz<int>(int) is callable
70
/// static_assert(has_member_fizz<Foo, int>::value_with_template_params<int>)
71
///
72
/// // check if Foo.fizz<int, double>() is callable
73
/// static_assert(!has_member_fizz<Foo>::value_with_template_params<int, double>)
74
/// \endcode
75
///
76
/// Explanation:
77
/// - To obtain \c value, the static member function \c test is instantiated
78
/// using the given type \c Type.
79
/// - Using declval, we get an instance of \c Type and try to call the expected
80
/// member function with instances of the passed \c MemberArgs.
81
/// - Optionally, \c test_with_template_params also instantiates the
82
/// functions template parameters with the passed types.
83
/// - If that member does not exist, we can not obtain the \c decltype, and cannot
84
/// instantiate \c std::void_t<...>, which fails to initialize the whole function
85
/// \c test(int).
86
/// - Then, the next best instantiation is \c test(long), which returns \c
87
/// std::false_type.
88
/// - If we find the requested member, we get \c std::true_type.
89
/// - \c test has \c int and \c long overloads to resolve ambiguity. Passing 0
90
/// to \c test ensure that we first try to instantiate the \c true variant.
91
#define KAMPING_MAKE_HAS_MEMBER(Member) \
92
template <typename Type, typename... MemberArgs> \
93
class has_member_##Member { \
94
template < \
95
typename C, \
96
typename = std::void_t<decltype(std::declval<C>().Member(std::declval<MemberArgs>()...))>> \
97
static auto test(int) -> std::true_type; \
98
template <typename C> \
99
static auto test(long) -> std::false_type; \
100
template < \
101
typename C, \
102
typename... TemplateParams, \
103
typename = std::void_t< \
104
decltype(std::declval<C>().template Member<TemplateParams...>(std::declval<MemberArgs>()...))>> \
105
static auto test_with_template_params(int) -> std::true_type; \
106
template <typename C, typename... TemplateParams> \
107
static auto test_with_template_params(long) -> std::false_type; \
108
\
109
public: \
110
static constexpr bool value = decltype(test<Type>(0))::value; \
111
\
112
template <typename... TemplateParams> \
113
static constexpr bool value_with_template_params = \
114
decltype(test_with_template_params<Type, TemplateParams...>(0))::value; \
115
}; \
116
\
117
template <typename Type, typename... MemberArgs> \
118
[[maybe_unused]] static constexpr bool has_member_##Member##_v = has_member_##Member<Type, MemberArgs...>::value;
include
kamping
has_member.hpp
Generated by
1.10.0