1/*============================================================================= 2 Copyright (c) 2014 Paul Fultz II 3 lambda.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_FUNCTION_LAMBDA_H 9#define BOOST_HOF_GUARD_FUNCTION_LAMBDA_H 10 11/// BOOST_HOF_STATIC_LAMBDA 12/// ================= 13/// 14/// Description 15/// ----------- 16/// 17/// The `BOOST_HOF_STATIC_LAMBDA` macro allows initializing non-capturing lambdas at 18/// compile-time in a `constexpr` expression. 19/// 20/// Example 21/// ------- 22/// 23/// #include <boost/hof.hpp> 24/// #include <cassert> 25/// 26/// const constexpr auto add_one = BOOST_HOF_STATIC_LAMBDA(int x) 27/// { 28/// return x + 1; 29/// }; 30/// 31/// int main() { 32/// assert(3 == add_one(2)); 33/// } 34/// 35/// BOOST_HOF_STATIC_LAMBDA_FUNCTION 36/// ========================== 37/// 38/// Description 39/// ----------- 40/// 41/// The `BOOST_HOF_STATIC_LAMBDA_FUNCTION` macro allows initializing a global 42/// function object that contains non-capturing lambdas. It also ensures that 43/// the global function object has a unique address across translation units. 44/// This helps prevent possible ODR-violations. 45/// 46/// By default, all functions defined with `BOOST_HOF_STATIC_LAMBDA_FUNCTION` use 47/// the `boost::hof::reveal` adaptor to improve error messages. 48/// 49/// Example 50/// ------- 51/// 52/// #include <boost/hof.hpp> 53/// #include <cassert> 54/// 55/// BOOST_HOF_STATIC_LAMBDA_FUNCTION(add_one) = [](int x) 56/// { 57/// return x + 1; 58/// }; 59/// int main() { 60/// assert(3 == add_one(2)); 61/// } 62/// 63 64#include <boost/hof/config.hpp> 65 66// TODO: Move this to a detail header 67#if !BOOST_HOF_HAS_CONSTEXPR_LAMBDA || !BOOST_HOF_HAS_INLINE_LAMBDAS 68 69#include <type_traits> 70#include <utility> 71#include <boost/hof/detail/result_of.hpp> 72#include <boost/hof/reveal.hpp> 73#include <boost/hof/detail/constexpr_deduce.hpp> 74#include <boost/hof/function.hpp> 75 76 77#ifndef BOOST_HOF_REWRITE_STATIC_LAMBDA 78#ifdef _MSC_VER 79#define BOOST_HOF_REWRITE_STATIC_LAMBDA 1 80#else 81#define BOOST_HOF_REWRITE_STATIC_LAMBDA 0 82#endif 83#endif 84 85namespace boost { namespace hof { 86 87namespace detail { 88 89template<class F> 90struct static_function_wrapper 91{ 92 // Default constructor necessary for MSVC 93 constexpr static_function_wrapper() 94 {} 95 96 static_assert(BOOST_HOF_IS_EMPTY(F), "Function or lambda expression must be empty"); 97 98 struct failure 99 : failure_for<F> 100 {}; 101 102 template<class... Ts> 103 const F& base_function(Ts&&...) const 104 { 105 return reinterpret_cast<const F&>(*this); 106 } 107 108 BOOST_HOF_RETURNS_CLASS(static_function_wrapper); 109 110 template<class... Ts> 111 BOOST_HOF_SFINAE_RESULT(const F&, id_<Ts>...) 112 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 113 ( 114 BOOST_HOF_RETURNS_REINTERPRET_CAST(const F&)(*BOOST_HOF_CONST_THIS)(BOOST_HOF_FORWARD(Ts)(xs)...) 115 ); 116}; 117 118struct static_function_wrapper_factor 119{ 120 constexpr static_function_wrapper_factor() 121 {} 122 template<class F> 123 constexpr static_function_wrapper<F> operator= (const F&) const 124 { 125 // static_assert(std::is_literal_type<static_function_wrapper<F>>::value, "Function wrapper not a literal type"); 126 return {}; 127 } 128}; 129 130#if BOOST_HOF_REWRITE_STATIC_LAMBDA 131template<class T, class=void> 132struct is_rewritable 133: std::false_type 134{}; 135 136template<class T> 137struct is_rewritable<T, typename detail::holder< 138 typename T::fit_rewritable_tag 139>::type> 140: std::is_same<typename T::fit_rewritable_tag, T> 141{}; 142 143template<class T, class=void> 144struct is_rewritable1 145: std::false_type 146{}; 147 148template<class T> 149struct is_rewritable1<T, typename detail::holder< 150 typename T::fit_rewritable1_tag 151>::type> 152: std::is_same<typename T::fit_rewritable1_tag, T> 153{}; 154 155 156template<class T, class=void> 157struct rewrite_lambda; 158 159template<template<class...> class Adaptor, class... Ts> 160struct rewrite_lambda<Adaptor<Ts...>, typename std::enable_if< 161 is_rewritable<Adaptor<Ts...>>::value 162>::type> 163{ 164 typedef Adaptor<typename rewrite_lambda<Ts>::type...> type; 165}; 166 167template<template<class...> class Adaptor, class T, class... Ts> 168struct rewrite_lambda<Adaptor<T, Ts...>, typename std::enable_if< 169 is_rewritable1<Adaptor<T, Ts...>>::value 170>::type> 171{ 172 typedef Adaptor<typename rewrite_lambda<T>::type, Ts...> type; 173}; 174 175template<class T> 176struct rewrite_lambda<T, typename std::enable_if< 177 std::is_empty<T>::value && 178 !is_rewritable<T>::value && 179 !is_rewritable1<T>::value 180>::type> 181{ 182 typedef static_function_wrapper<T> type; 183}; 184 185template<class T> 186struct rewrite_lambda<T, typename std::enable_if< 187 !std::is_empty<T>::value && 188 !is_rewritable<T>::value && 189 !is_rewritable1<T>::value 190>::type> 191{ 192 typedef T type; 193}; 194 195#endif 196 197template<class T> 198struct reveal_static_lambda_function_wrapper_factor 199{ 200 constexpr reveal_static_lambda_function_wrapper_factor() 201 {} 202#if BOOST_HOF_REWRITE_STATIC_LAMBDA 203 template<class F> 204 constexpr reveal_adaptor<typename rewrite_lambda<F>::type> 205 operator=(const F&) const 206 { 207 return reveal_adaptor<typename rewrite_lambda<F>::type>(); 208 } 209#elif BOOST_HOF_HAS_CONST_FOLD 210 template<class F> 211 constexpr const reveal_adaptor<F>& operator=(const F&) const 212 { 213 return reinterpret_cast<const reveal_adaptor<F>&>(static_const_var<T>()); 214 } 215#else 216 template<class F> 217 constexpr reveal_adaptor<static_function_wrapper<F>> operator=(const F&) const 218 { 219 return {}; 220 } 221#endif 222}; 223 224}}} // namespace boost::hof 225 226#endif 227 228#if BOOST_HOF_HAS_CONSTEXPR_LAMBDA 229#define BOOST_HOF_STATIC_LAMBDA [] 230#else 231#define BOOST_HOF_DETAIL_MAKE_STATIC BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE boost::hof::detail::static_function_wrapper_factor() 232#define BOOST_HOF_STATIC_LAMBDA BOOST_HOF_DETAIL_MAKE_STATIC = [] 233#endif 234 235#if BOOST_HOF_HAS_INLINE_LAMBDAS 236#define BOOST_HOF_STATIC_LAMBDA_FUNCTION BOOST_HOF_STATIC_FUNCTION 237#else 238#define BOOST_HOF_DETAIL_MAKE_REVEAL_STATIC(T) BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE_UNIQUE(T) boost::hof::detail::reveal_static_lambda_function_wrapper_factor<T>() 239#define BOOST_HOF_STATIC_LAMBDA_FUNCTION(name) \ 240struct fit_private_static_function_ ## name {}; \ 241BOOST_HOF_STATIC_AUTO_REF name = BOOST_HOF_DETAIL_MAKE_REVEAL_STATIC(fit_private_static_function_ ## name) 242#endif 243 244#endif 245