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