KDBindings API Documentation  1.0.95
utils.h
Go to the documentation of this file.
1 /*
2  This file is part of KDBindings.
3 
4  SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5  Author: Leon Matthes <leon.matthes@kdab.com>
6 
7  SPDX-License-Identifier: MIT
8 
9  Contact KDAB at <info@kdab.com> for commercial licensing options.
10 */
11 #pragma once
12 
13 #include <functional>
14 #include <type_traits>
15 #include <utility>
16 
17 namespace KDBindings {
18 
24 namespace Private {
25 
26 // ------------------------ get_arity --------------------------
27 // get_arity is a template function that returns the number of arguments
28 // of (almost) any callable object.
29 // The easiest way is to simply call get_arity<T>() for callable type T.
30 // It needs to be constexpr in order so it can be used in template arguments.
31 
32 // To overload get_arity, it needs a marker type, as C++ doesn't allow partial
33 // function specialization.
34 template<typename T>
35 struct TypeMarker {
36  constexpr TypeMarker() = default;
37 };
38 
39 // base implementation of get_arity refers to specialized implementations for each
40 // type of callable object by using the overload for its specialized TypeMarker.
41 template<typename T>
42 constexpr size_t get_arity()
43 {
44  return get_arity(TypeMarker<std::decay_t<T>>{});
45 }
46 
47 // Syntactic sugar version of get_arity, allows to pass any callable object
48 // to get_arity, instead of having to pass its decltype as a template argument.
49 template<typename T>
50 constexpr size_t get_arity(const T &)
51 {
52  return get_arity<T>();
53 }
54 
55 // The arity of a function pointer is simply its number of arguments.
56 template<typename Return, typename... Arguments>
57 constexpr size_t get_arity(TypeMarker<Return (*)(Arguments...)>)
58 {
59  return sizeof...(Arguments);
60 }
61 
62 template<typename Return, typename... Arguments>
63 constexpr size_t get_arity(TypeMarker<Return (*)(Arguments...) noexcept>)
64 {
65  return sizeof...(Arguments);
66 }
67 
68 // The arity of a generic callable object is the arity of its operator() - 1, as the this
69 // pointer is already known for such an object.
70 template<typename T>
71 constexpr size_t get_arity(TypeMarker<T>)
72 {
73  return get_arity(TypeMarker<decltype(&T::operator())>{}) - 1;
74 }
75 
76 // Macro to help define most combinations of possible member function qualifiers.
77 // Add + 1 to sizeof...(Arguments) here as the "this" pointer is an implicit argument to any member function.
78 #define KDBINDINGS_DEFINE_MEMBER_GET_ARITY(MODIFIERS) \
79  template<typename Return, typename Class, typename... Arguments> \
80  constexpr size_t get_arity(::KDBindings::Private::TypeMarker<Return (Class::*)(Arguments...) MODIFIERS>) \
81  { \
82  return sizeof...(Arguments) + 1; \
83  }
84 
85 // Define the get_arity version without modifiers without using the macro.
86 // MSVC otherwise complains about a call to the macro with too few arguments
87 template<typename Return, typename Class, typename... Arguments>
88 constexpr size_t get_arity(::KDBindings::Private::TypeMarker<Return (Class::*)(Arguments...)>)
89 {
90  return sizeof...(Arguments) + 1;
91 }
92 
98 
102 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile const &)
104 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile const &&)
105 
109 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(const &noexcept)
111 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(const &&noexcept)
112 
113 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile noexcept)
114 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile const noexcept)
115 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile &noexcept)
116 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile const &noexcept)
117 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile &&noexcept)
118 KDBINDINGS_DEFINE_MEMBER_GET_ARITY(volatile const &&noexcept)
119 
120 // -------------------- placeholder and bind_first ---------------------
121 // Inspired by https://gist.github.com/engelmarkus/fc1678adbed1b630584c90219f77eb48
122 // A placeholder provides a way to construct something equivalent to a std::placeholders::_N
123 // with N as a template argument.
124 //
125 // Note: As placeholders start at 1, therefore placeholder<0> is NOT a valid placeholder.
126 template<int>
127 struct placeholder {
128 };
129 
130 template<typename Func, typename... Args, std::size_t... Is>
131 auto bind_first_helper(std::index_sequence<Is...>, Func &&fun, Args... args)
132 {
133  return std::bind(std::forward<Func>(fun), std::forward<Args>(args)..., placeholder<Is + 1>{}...);
134 }
135 
136 // bind_first binds the first arguments to the callable object (i.e. function) to the values provided by args.
137 // The return value is a new function taking get_arity<Func> - sizeof...(Args) many arguments, with the first
138 // sizeof...(Args) arguments bound to the values of args.
139 // This is different to a call with std::bind(fun, args...), as the callable object created by std::bind would
140 // in this case now take zero arguments, whilst bind_first still expects the remaining arguments to be provided
141 //
142 // For now, providing instances of std::placeholders in Args is not allowed, as the implications of this are
143 // unclear if sizeof...(Args) != get_arity<Func>. The enable_if_t makes sure none of the Args value is a placeholder.
144 //
145 // In the future, we could provide another overload of this function that allows placeholders, as long as all arguments
146 // are bound.
147 template<
148  typename Func,
149  typename... Args,
150  /*Disallow any placeholder arguments, they would mess with the number and ordering of required and bound arguments, and are, for now, unsupported*/
151  typename = std::enable_if_t<std::conjunction_v<std::negation<std::is_placeholder<Args>>...>>>
152 auto bind_first(Func &&fun, Args &&...args)
153 {
154  return bind_first_helper(std::make_index_sequence<get_arity<Func>() - sizeof...(Args)>{}, std::forward<Func>(fun), std::forward<Args>(args)...);
155 }
156 
157 } // namespace Private
158 
159 } // namespace KDBindings
160 
161 namespace std {
162 
163 // This allows a placeholder to be used as a replacement of a std::placeholders.
164 template<int N>
165 struct is_placeholder<KDBindings::Private::placeholder<N>>
166  : integral_constant<int, N> {
167 };
168 
169 } // namespace std
The main namespace of the KDBindings library.
Definition: binding.h:21
Definition: utils.h:161
#define KDBINDINGS_DEFINE_MEMBER_GET_ARITY(MODIFIERS)
Definition: utils.h:78

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDBindings
Reactive programming & data binding in C++
https://github.com/KDAB/KDBindings/
Generated by doxygen 1.9.1