1 /*=============================================================================
2 Copyright (c) 2014 Paul Fultz II
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 ==============================================================================*/
8 #ifndef BOOST_HOF_GUARD_FUNCTION_LAMBDA_H
9 #define BOOST_HOF_GUARD_FUNCTION_LAMBDA_H
11 /// BOOST_HOF_STATIC_LAMBDA
17 /// The `BOOST_HOF_STATIC_LAMBDA` macro allows initializing non-capturing lambdas at
18 /// compile-time in a `constexpr` expression.
23 /// #include <boost/hof.hpp>
24 /// #include <cassert>
26 /// const constexpr auto add_one = BOOST_HOF_STATIC_LAMBDA(int x)
32 /// assert(3 == add_one(2));
35 /// BOOST_HOF_STATIC_LAMBDA_FUNCTION
36 /// ==========================
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.
46 /// By default, all functions defined with `BOOST_HOF_STATIC_LAMBDA_FUNCTION` use
47 /// the `boost::hof::reveal` adaptor to improve error messages.
49 /// Note: due to compiler limitations, a global function declared with
50 /// `BOOST_HOF_STATIC_LAMBDA_FUNCTION` is not guaranteed to have a unique
51 /// address across translation units when compiled with pre-C++17 MSVC.
56 /// #include <boost/hof.hpp>
57 /// #include <cassert>
59 /// BOOST_HOF_STATIC_LAMBDA_FUNCTION(add_one) = [](int x)
64 /// assert(3 == add_one(2));
68 #include <boost/hof/config.hpp>
70 // TODO: Move this to a detail header
71 #if !BOOST_HOF_HAS_CONSTEXPR_LAMBDA || !BOOST_HOF_HAS_INLINE_LAMBDAS
73 #include <type_traits>
75 #include <boost/hof/detail/result_of.hpp>
76 #include <boost/hof/reveal.hpp>
77 #include <boost/hof/detail/constexpr_deduce.hpp>
78 #include <boost/hof/function.hpp>
81 #ifndef BOOST_HOF_REWRITE_STATIC_LAMBDA
83 #define BOOST_HOF_REWRITE_STATIC_LAMBDA 1
85 #define BOOST_HOF_REWRITE_STATIC_LAMBDA 0
89 namespace boost { namespace hof {
94 struct static_function_wrapper
96 // Default constructor necessary for MSVC
97 constexpr static_function_wrapper()
100 static_assert(BOOST_HOF_IS_EMPTY(F), "Function or lambda expression must be empty");
106 template<class... Ts>
107 const F& base_function(Ts&&...) const
109 return reinterpret_cast<const F&>(*this);
112 BOOST_HOF_RETURNS_CLASS(static_function_wrapper);
114 template<class... Ts>
115 BOOST_HOF_SFINAE_RESULT(const F&, id_<Ts>...)
116 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
118 BOOST_HOF_RETURNS_REINTERPRET_CAST(const F&)(*BOOST_HOF_CONST_THIS)(BOOST_HOF_FORWARD(Ts)(xs)...)
122 struct static_function_wrapper_factor
124 constexpr static_function_wrapper_factor()
127 constexpr static_function_wrapper<F> operator= (const F&) const
129 // static_assert(std::is_literal_type<static_function_wrapper<F>>::value, "Function wrapper not a literal type");
134 #if BOOST_HOF_REWRITE_STATIC_LAMBDA
135 template<class T, class=void>
141 struct is_rewritable<T, typename detail::holder<
142 typename T::fit_rewritable_tag
144 : std::is_same<typename T::fit_rewritable_tag, T>
147 template<class T, class=void>
148 struct is_rewritable1
153 struct is_rewritable1<T, typename detail::holder<
154 typename T::fit_rewritable1_tag
156 : std::is_same<typename T::fit_rewritable1_tag, T>
160 template<class T, class=void>
161 struct rewrite_lambda;
163 template<template<class...> class Adaptor, class... Ts>
164 struct rewrite_lambda<Adaptor<Ts...>, typename std::enable_if<
165 is_rewritable<Adaptor<Ts...>>::value
168 typedef Adaptor<typename rewrite_lambda<Ts>::type...> type;
171 template<template<class...> class Adaptor, class T, class... Ts>
172 struct rewrite_lambda<Adaptor<T, Ts...>, typename std::enable_if<
173 is_rewritable1<Adaptor<T, Ts...>>::value
176 typedef Adaptor<typename rewrite_lambda<T>::type, Ts...> type;
180 struct rewrite_lambda<T, typename std::enable_if<
181 std::is_empty<T>::value &&
182 !is_rewritable<T>::value &&
183 !is_rewritable1<T>::value
186 typedef static_function_wrapper<T> type;
190 struct rewrite_lambda<T, typename std::enable_if<
191 !std::is_empty<T>::value &&
192 !is_rewritable<T>::value &&
193 !is_rewritable1<T>::value
202 struct reveal_static_lambda_function_wrapper_factor
204 constexpr reveal_static_lambda_function_wrapper_factor()
206 #if BOOST_HOF_REWRITE_STATIC_LAMBDA
208 constexpr reveal_adaptor<typename rewrite_lambda<F>::type>
209 operator=(const F&) const
211 return reveal_adaptor<typename rewrite_lambda<F>::type>();
213 #elif BOOST_HOF_HAS_CONST_FOLD
215 constexpr const reveal_adaptor<F>& operator=(const F&) const
217 return reinterpret_cast<const reveal_adaptor<F>&>(static_const_var<T>());
221 constexpr reveal_adaptor<static_function_wrapper<F>> operator=(const F&) const
228 }}} // namespace boost::hof
232 #if BOOST_HOF_HAS_CONSTEXPR_LAMBDA
233 #define BOOST_HOF_STATIC_LAMBDA []
235 #define BOOST_HOF_DETAIL_MAKE_STATIC BOOST_HOF_DETAIL_CONSTEXPR_DEDUCE boost::hof::detail::static_function_wrapper_factor()
236 #define BOOST_HOF_STATIC_LAMBDA BOOST_HOF_DETAIL_MAKE_STATIC = []
239 #if BOOST_HOF_HAS_INLINE_LAMBDAS
240 #define BOOST_HOF_STATIC_LAMBDA_FUNCTION BOOST_HOF_STATIC_FUNCTION
242 #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>()
243 #define BOOST_HOF_STATIC_LAMBDA_FUNCTION(name) \
244 struct fit_private_static_function_ ## name {}; \
245 BOOST_HOF_STATIC_AUTO_REF name = BOOST_HOF_DETAIL_MAKE_REVEAL_STATIC(fit_private_static_function_ ## name)