-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFunctional.h
213 lines (191 loc) · 7.59 KB
/
Functional.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/**
* \copyright
* Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*
*/
#pragma once
#include <functional>
#include "BaseLib/TMPUtil.h"
namespace BaseLib
{
namespace detail
{
//! Helper struct used to make std::placeholders::_1, ... accessible via a
//! compile-time computed index (the template parameter).
template <int>
struct IndexedPlacedPlaceholder;
//! Creates specializations of IndexedPlacedPlaceholder.
//! \param INDEX the integer value which is specialized
//! \param INDEX_P_1 "index plus one"; if INDEX_P_1 equals 1, then the member
//! value will be std::placeholders::_1, etc.
#define SPECIALIZE_INDEXEDPLACEHOLDER(INDEX, INDEX_P_1) \
template <> \
struct IndexedPlacedPlaceholder<(INDEX)> { \
static const decltype(std::placeholders::_##INDEX_P_1) value; \
}
// Create specializations up to the tenth placeholder
SPECIALIZE_INDEXEDPLACEHOLDER(0, 1);
SPECIALIZE_INDEXEDPLACEHOLDER(1, 2);
SPECIALIZE_INDEXEDPLACEHOLDER(2, 3);
SPECIALIZE_INDEXEDPLACEHOLDER(3, 4);
SPECIALIZE_INDEXEDPLACEHOLDER(4, 5);
SPECIALIZE_INDEXEDPLACEHOLDER(5, 6);
SPECIALIZE_INDEXEDPLACEHOLDER(6, 7);
SPECIALIZE_INDEXEDPLACEHOLDER(7, 8);
SPECIALIZE_INDEXEDPLACEHOLDER(8, 9);
SPECIALIZE_INDEXEDPLACEHOLDER(9, 10);
#undef SPECIALIZE_INDEXEDPLACEHOLDER
// Note: The call sequence is easyBind() -> easyBind_inner() ->
// easyBind_innermost().
template <int... Indices, typename Object, typename ReturnType,
typename... Args>
std::function<ReturnType(Args...)> easyBind_innermost(
ReturnType (Object::*method)(Args...), Object& obj)
{
// std::ref makes sure that obj is not copied.
return std::bind(method, std::ref(obj),
IndexedPlacedPlaceholder<Indices>::value...);
}
template <int... Indices, typename Object, typename ReturnType,
typename... Args>
std::function<ReturnType(Args...)> easyBind_innermost(
ReturnType (Object::*method)(Args...) const, Object const& obj)
{
// std::cref makes sure that obj is not copied.
return std::bind(method, std::cref(obj),
IndexedPlacedPlaceholder<Indices>::value...);
}
template <int... Indices, typename Object, typename ReturnType,
typename... Args>
std::function<ReturnType(Args...)> easyBind_innermost(
ReturnType (Object::*method)(Args...) const, Object& obj)
{
// std::cref makes sure that obj is not copied.
return std::bind(method, std::cref(obj),
IndexedPlacedPlaceholder<Indices>::value...);
}
template <int... Indices, typename Object, typename MethodClass,
typename ReturnType, typename... Args>
std::function<ReturnType(Args...)> easyBind_innermost(
ReturnType (MethodClass::*method)(Args...), Object&& obj)
{
return std::bind(method, std::forward<Object>(obj),
IndexedPlacedPlaceholder<Indices>::value...);
}
template <int... Indices, typename Object, typename MethodClass,
typename ReturnType, typename... Args>
std::function<ReturnType(Args...)> easyBind_innermost(
ReturnType (MethodClass::*method)(Args...) const, Object&& obj)
{
return std::bind(method, std::forward<Object>(obj),
IndexedPlacedPlaceholder<Indices>::value...);
}
template <int... Indices, typename Object, typename MethodClass,
typename ReturnType, typename... Args>
std::function<ReturnType(Args...)> easyBind_inner(
ReturnType (MethodClass::*method)(Args...), Object&& obj,
IntegerSequence<Indices...>)
{
return easyBind_innermost<Indices...>(method, std::forward<Object>(obj));
}
template <int... Indices, typename Object, typename MethodClass,
typename ReturnType, typename... Args>
std::function<ReturnType(Args...)> easyBind_inner(
ReturnType (MethodClass::*method)(Args...) const, Object&& obj,
IntegerSequence<Indices...>)
{
return easyBind_innermost<Indices...>(method, std::forward<Object>(obj));
}
/*! Deduces the signature of the call operator of class \c T.
*
* The matching type of std::function is provided as the member type
* \c FunctionType.
*
* \see http://stackoverflow.com/a/7943765
*/
template <typename T>
struct FunctionTraits
: public FunctionTraits<decltype(&std::decay<T>::type::operator())> {
};
template <typename Object, typename ReturnType, typename... Args>
struct FunctionTraits<ReturnType (Object::*)(Args...)> {
using FunctionType = std::function<ReturnType(Args...)>;
};
template <typename Object, typename ReturnType, typename... Args>
struct FunctionTraits<ReturnType (Object::*)(Args...) const> {
using FunctionType = std::function<ReturnType(Args...)>;
};
} // namespace detail
/*! Convenience wrapper for std::bind().
*
* This function binds the member function pointer \c member of class \c Object
* to the instance \c obj of this class and wraps the result in a std::function
* with matching signature.
*
* The result of this function can be used, e.g., to deduce the signature of the
* \c method (which is not possible with the result of std::bind).
*
* Example:
* \code{.cpp}
* using std::placeholders;
* Object some_object;
*
* auto f_bind = std::function<ReturnType(Arg1, Arg2, Arg3>(
* std::bind(&Object::methodWithThreeArguments,
* std::ref(some_object), _1, _2, _3));
*
* auto f_easy = easyBind(&Object::methodWithThreeArguments, some_object);
* \endcode
*
* In the example the expressions creating \c f_bind and \c f_easy are
* equivalent.
*
* \note
* There is one difference between the behaviour of std::bind and the one of
* easyBind: In easyBind \c obj is never copied, instead it will be referenced.
* This is in contrast to the behaviour of std::bind, and has been chosen in
* order to prevent accidental copies.
*/
template <typename Object, typename MethodClass, typename ReturnType,
typename... Args>
typename std::enable_if<
std::is_same<MethodClass,
/* Note: All of remove_cv, remove_pointer and decay is
* necessary, e.g. if method is a member function pointer. */
typename std::remove_cv<typename std::remove_pointer<
typename std::decay<Object>::type>::type>::type>::value,
std::function<ReturnType(Args...)>>::type
easyBind(ReturnType (MethodClass::*method)(Args...), Object&& obj)
{
return detail::easyBind_inner(
method, std::forward<Object>(obj),
typename GenerateIntegerSequence<sizeof...(Args)>::type{});
}
//! \overload
template <typename Object, typename MethodClass, typename ReturnType,
typename... Args>
typename std::enable_if<
std::is_same<MethodClass,
typename std::remove_cv<typename std::remove_pointer<
typename std::decay<Object>::type>::type>::type>::value,
std::function<ReturnType(Args...)>>::type
easyBind(ReturnType (MethodClass::*method)(Args...) const, Object&& obj)
{
return detail::easyBind_inner(
method, std::forward<Object>(obj),
typename GenerateIntegerSequence<sizeof...(Args)>::type{});
}
//! Wraps a callable object in a std::function.
//!
//! This method is provided for convenience since it automatically deduces the
//! correct type of std::function.
template <typename Object>
typename detail::FunctionTraits<Object>::FunctionType easyBind(Object&& obj)
{
return BaseLib::easyBind(&std::decay<Object>::type::operator(),
std::forward<Object>(obj));
}
} // namespace BaseLib