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