1 /*=============================================================================
2     Copyright (c) 2014 Paul Fultz II
3     returns.h
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 
8 #ifndef BOOST_HOF_GUARD_RETURNS_H
9 #define BOOST_HOF_GUARD_RETURNS_H
10 
11 /// BOOST_HOF_RETURNS
12 /// ===========
13 ///
14 /// Description
15 /// -----------
16 ///
17 /// The `BOOST_HOF_RETURNS` macro defines the function as the expression
18 /// equivalence. It does this by deducing `noexcept` and the return type by
19 /// using a trailing `decltype`. Instead of repeating the expression for the
20 /// return type, `noexcept` clause and the function body, this macro will
21 /// reduce the code duplication from that.
22 ///
23 /// Note: The expression used to deduce the return the type will also
24 /// constrain the template function and deduce `noexcept` as well, which is
25 /// different behaviour than using C++14's return type deduction.
26 ///
27 /// Synopsis
28 /// --------
29 ///
30 ///     #define BOOST_HOF_RETURNS(...)
31 ///
32 ///
33 /// Example
34 /// -------
35 ///
36 ///     #include <boost/hof.hpp>
37 ///     #include <cassert>
38 ///
39 ///     template<class T, class U>
40 ///     auto sum(T x, U y) BOOST_HOF_RETURNS(x+y);
41 ///
42 ///     int main() {
43 ///         assert(3 == sum(1, 2));
44 ///     }
45 ///
46 ///
47 /// Incomplete this
48 /// ---------------
49 ///
50 /// Description
51 /// -----------
52 ///
53 /// On some non-conformant compilers, such as gcc, the `this` variable cannot
54 /// be used inside the `BOOST_HOF_RETURNS` macro because it is considered an
55 /// incomplete type. So the following macros are provided to help workaround
56 /// the issue.
57 ///
58 ///
59 /// Synopsis
60 /// --------
61 ///
62 ///     // Declares the type of the `this` variable
63 ///     #define BOOST_HOF_RETURNS_CLASS(...)
64 ///     // Used to refer to the `this` variable in the BOOST_HOF_RETURNS macro
65 ///     #define BOOST_HOF_THIS
66 ///     // Used to refer to the const `this` variable in the BOOST_HOF_RETURNS macro
67 ///     #define BOOST_HOF_CONST_THIS
68 ///
69 ///
70 /// Example
71 /// -------
72 ///
73 ///     #include <boost/hof.hpp>
74 ///     #include <cassert>
75 ///
76 ///     struct add_1
77 ///     {
78 ///         int a;
79 ///         add_1() : a(1) {}
80 ///
81 ///         BOOST_HOF_RETURNS_CLASS(add_1);
82 ///
83 ///         template<class T>
84 ///         auto operator()(T x) const
85 ///         BOOST_HOF_RETURNS(x+BOOST_HOF_CONST_THIS->a);
86 ///     };
87 ///
88 ///     int main() {
89 ///         assert(3 == add_1()(2));
90 ///     }
91 ///
92 ///
93 /// Mangling overloads
94 /// ------------------
95 ///
96 /// Description
97 /// -----------
98 ///
99 /// On older compilers some operations done in the expressions cannot be
100 /// properly mangled. These macros help provide workarounds for these
101 /// operations on older compilers.
102 ///
103 ///
104 /// Synopsis
105 /// --------
106 ///
107 ///     // Explicitly defines the type for name mangling
108 ///     #define BOOST_HOF_MANGLE_CAST(...)
109 ///     // C cast for name mangling
110 ///     #define BOOST_HOF_RETURNS_C_CAST(...)
111 ///     // Reinterpret cast for name mangling
112 ///     #define BOOST_HOF_RETURNS_REINTERPRET_CAST(...)
113 ///     // Static cast for name mangling
114 ///     #define BOOST_HOF_RETURNS_STATIC_CAST(...)
115 ///     // Construction for name mangling
116 ///     #define BOOST_HOF_RETURNS_CONSTRUCT(...)
117 ///
118 
119 
120 #include <boost/hof/config.hpp>
121 #include <utility>
122 #include <boost/hof/detail/forward.hpp>
123 #include <boost/hof/detail/noexcept.hpp>
124 
125 #define BOOST_HOF_EAT(...)
126 #define BOOST_HOF_REM(...) __VA_ARGS__
127 
128 #if BOOST_HOF_HAS_COMPLETE_DECLTYPE && BOOST_HOF_HAS_MANGLE_OVERLOAD
129 #ifdef _MSC_VER
130 // Since decltype can't be used in noexcept on MSVC, we can't check for noexcept
131 // move constructors.
132 #define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(__VA_ARGS__))
133 #else
134 #define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(static_cast<decltype(__VA_ARGS__)>(__VA_ARGS__)))
135 #endif
136 #define BOOST_HOF_RETURNS(...) \
137 BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) \
138 -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
139 #define BOOST_HOF_THIS this
140 #define BOOST_HOF_CONST_THIS this
141 #define BOOST_HOF_RETURNS_CLASS(...) \
142 void fit_returns_class_check() \
143 { \
144     static_assert(std::is_same<__VA_ARGS__*, decltype(this)>::value, \
145         "Returns class " #__VA_ARGS__ " type doesn't match"); \
146 }
147 
148 #define BOOST_HOF_MANGLE_CAST(...) BOOST_HOF_REM
149 
150 #define BOOST_HOF_RETURNS_C_CAST(...) (__VA_ARGS__) BOOST_HOF_REM
151 #define BOOST_HOF_RETURNS_REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__>
152 #define BOOST_HOF_RETURNS_STATIC_CAST(...) static_cast<__VA_ARGS__>
153 #define BOOST_HOF_RETURNS_CONSTRUCT(...) __VA_ARGS__
154 #else
155 #include <boost/hof/detail/pp.hpp>
156 
157 #define BOOST_HOF_RETURNS_RETURN(...) return BOOST_HOF_RETURNS_RETURN_X(BOOST_HOF_PP_WALL(__VA_ARGS__))
158 #define BOOST_HOF_RETURNS_RETURN_X(...) __VA_ARGS__
159 
160 #ifdef _MSC_VER
161 // Since decltype can't be used in noexcept on MSVC, we can't check for noexcept
162 // move constructors.
163 #define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__)))
164 #else
165 #define BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(...) BOOST_HOF_NOEXCEPT(noexcept(static_cast<decltype(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__))>(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__))))
166 #endif
167 
168 #define BOOST_HOF_RETURNS_DECLTYPE(...) \
169 -> decltype(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(__VA_ARGS__))
170 
171 #define BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(...) BOOST_HOF_RETURNS_DECLTYPE_CONTEXT_X(BOOST_HOF_PP_WALL(__VA_ARGS__))
172 #define BOOST_HOF_RETURNS_DECLTYPE_CONTEXT_X(...) __VA_ARGS__
173 
174 #define BOOST_HOF_RETURNS_THAT(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\
175     (boost::hof::detail::check_this<__VA_ARGS__, decltype(this)>(), this), \
176     std::declval<__VA_ARGS__>() \
177 )
178 
179 #define BOOST_HOF_THIS BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_THAT)(fit_this_type)
180 #define BOOST_HOF_CONST_THIS BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_THAT)(fit_const_this_type)
181 
182 #define BOOST_HOF_RETURNS_CLASS(...) typedef __VA_ARGS__* fit_this_type; typedef const __VA_ARGS__* fit_const_this_type
183 
184 #define BOOST_HOF_RETURNS(...) \
185 BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) \
186 BOOST_HOF_RETURNS_DECLTYPE(__VA_ARGS__) \
187 { BOOST_HOF_RETURNS_RETURN(__VA_ARGS__); }
188 
189 
190 namespace boost { namespace hof { namespace detail {
191 template<class Assumed, class T>
192 struct check_this
193 {
194     static_assert(std::is_same<T, Assumed>::value, "Incorret BOOST_HOF_THIS or BOOST_HOF_CONST_THIS used.");
195 };
196 
197 }}} // namespace boost::hof
198 
199 #endif
200 
201 
202 #if BOOST_HOF_HAS_MANGLE_OVERLOAD
203 
204 #define BOOST_HOF_MANGLE_CAST(...) BOOST_HOF_REM
205 
206 #define BOOST_HOF_RETURNS_C_CAST(...) (__VA_ARGS__) BOOST_HOF_REM
207 #define BOOST_HOF_RETURNS_REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__>
208 #define BOOST_HOF_RETURNS_STATIC_CAST(...) static_cast<__VA_ARGS__>
209 #define BOOST_HOF_RETURNS_CONSTRUCT(...) __VA_ARGS__
210 
211 #else
212 
213 #define BOOST_HOF_RETURNS_DERAIL_MANGLE_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\
214     BOOST_HOF_REM, \
215     std::declval<__VA_ARGS__>() BOOST_HOF_EAT \
216 )
217 #define BOOST_HOF_MANGLE_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_MANGLE_CAST)
218 
219 
220 #define BOOST_HOF_RETURNS_DERAIL_C_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\
221     (__VA_ARGS__) BOOST_HOF_REM, \
222     std::declval<__VA_ARGS__>() BOOST_HOF_EAT \
223 )
224 #define BOOST_HOF_RETURNS_C_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_C_CAST)
225 
226 
227 #define BOOST_HOF_RETURNS_DERAIL_REINTERPRET_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\
228     reinterpret_cast<__VA_ARGS__>, \
229     std::declval<__VA_ARGS__>() BOOST_HOF_EAT \
230 )
231 #define BOOST_HOF_RETURNS_REINTERPRET_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_REINTERPRET_CAST)
232 
233 #define BOOST_HOF_RETURNS_DERAIL_STATIC_CAST(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\
234     static_cast<__VA_ARGS__>, \
235     std::declval<__VA_ARGS__>() BOOST_HOF_EAT \
236 )
237 #define BOOST_HOF_RETURNS_STATIC_CAST BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_STATIC_CAST)
238 
239 #define BOOST_HOF_RETURNS_DERAIL_CONSTRUCT(...) BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_RETURNS_DECLTYPE_CONTEXT(())))(\
240     __VA_ARGS__, \
241     std::declval<__VA_ARGS__>() BOOST_HOF_EAT \
242 )
243 #define BOOST_HOF_RETURNS_CONSTRUCT BOOST_HOF_PP_RAIL(BOOST_HOF_RETURNS_DERAIL_CONSTRUCT)
244 
245 #endif
246 
247 #define BOOST_HOF_AUTO_FORWARD(...) BOOST_HOF_RETURNS_STATIC_CAST(decltype(__VA_ARGS__))(__VA_ARGS__)
248 
249 #endif
250