• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(...) \
137BOOST_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(...) \
142void 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(...) \
185BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(__VA_ARGS__) \
186BOOST_HOF_RETURNS_DECLTYPE(__VA_ARGS__) \
187{ BOOST_HOF_RETURNS_RETURN(__VA_ARGS__); }
188
189
190namespace boost { namespace hof { namespace detail {
191template<class Assumed, class T>
192struct 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