Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:15

0001 /*=============================================================================
0002     Copyright (c) 2012 Paul Fultz II
0003     first_of.h
0004     Distributed under the Boost Software License, Version 1.0. (See accompanying
0005     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 ==============================================================================*/
0007 
0008 #ifndef BOOST_HOF_GUARD_FUNCTION_CONDITIONAL_H
0009 #define BOOST_HOF_GUARD_FUNCTION_CONDITIONAL_H
0010 
0011 /// first_of
0012 /// ========
0013 /// 
0014 /// Description
0015 /// -----------
0016 /// 
0017 /// The `first_of` function adaptor combines several functions together. If
0018 /// the first function can not be called, then it will try to call the next
0019 /// function. This can be very useful when overloading functions using
0020 /// template constraints(such as with `enable_if`).
0021 /// 
0022 /// Note: This is different than the [`match`](match.md) function adaptor, which
0023 /// can lead to ambiguities. Instead, `first_of` will call the first function
0024 /// that is callable, regardless if there is another function that could be
0025 /// called as well.
0026 /// 
0027 /// Synopsis
0028 /// --------
0029 /// 
0030 ///     template<class... Fs>
0031 ///     constexpr first_of_adaptor<Fs...> first_of(Fs... fs);
0032 /// 
0033 /// Requirements
0034 /// ------------
0035 /// 
0036 /// Fs must be:
0037 /// 
0038 /// * [ConstInvocable](ConstInvocable)
0039 /// * MoveConstructible
0040 /// 
0041 /// Example
0042 /// -------
0043 /// 
0044 ///     #include <boost/hof.hpp>
0045 ///     #include <iostream>
0046 ///     using namespace boost::hof;
0047 /// 
0048 ///     struct for_ints
0049 ///     {
0050 ///         void operator()(int) const
0051 ///         {
0052 ///             printf("Int\n");
0053 ///         }
0054 ///     };
0055 /// 
0056 ///     struct for_floats
0057 ///     {
0058 ///         void operator()(float) const
0059 ///         {
0060 ///             printf("Float\n");
0061 ///         }
0062 ///     };
0063 /// 
0064 ///     int main() {
0065 ///         first_of(for_ints(), for_floats())(3.0);
0066 ///     }
0067 /// 
0068 /// This will print `Int` because the `for_floats` function object won't ever be
0069 /// called. Due to the conversion rules in C++, the `for_ints` function can be
0070 /// called on floats, so it is chosen by `first_of` first, even though
0071 /// `for_floats` is a better match.
0072 /// 
0073 /// So, the order of the functions in the `first_of_adaptor` are very important
0074 /// to how the function is chosen.
0075 /// 
0076 /// References
0077 /// ----------
0078 /// 
0079 /// * [POO51](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0051r2.pdf) - Proposal for C++
0080 ///   Proposal for C++ generic overload function
0081 /// * [Conditional overloading](<Conditional overloading>)
0082 /// 
0083 
0084 #include <boost/hof/reveal.hpp>
0085 #include <boost/hof/detail/compressed_pair.hpp>
0086 #include <boost/hof/detail/callable_base.hpp>
0087 #include <boost/hof/detail/delegate.hpp>
0088 #include <boost/hof/detail/join.hpp>
0089 #include <boost/hof/detail/seq.hpp>
0090 #include <boost/hof/detail/make.hpp>
0091 #include <boost/hof/detail/static_const_var.hpp>
0092 
0093 namespace boost { namespace hof {
0094 
0095 namespace detail {
0096 
0097 template<class F1, class F2>
0098 struct basic_first_of_adaptor : F1, F2
0099 {
0100     BOOST_HOF_INHERIT_DEFAULT(basic_first_of_adaptor, F1, F2)
0101 
0102     template<class A, class B,
0103         BOOST_HOF_ENABLE_IF_CONVERTIBLE(A, F1),
0104         BOOST_HOF_ENABLE_IF_CONVERTIBLE(B, F2)>
0105     constexpr basic_first_of_adaptor(A&& f1, B&& f2)
0106     noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F1, A&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F2, B&&))
0107     : F1(BOOST_HOF_FORWARD(A)(f1)), F2(BOOST_HOF_FORWARD(B)(f2))
0108     {}
0109 
0110     template<class X,
0111         class=typename std::enable_if<
0112         BOOST_HOF_IS_CONVERTIBLE(X, F1) && 
0113         BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(F2)
0114     >::type>
0115     constexpr basic_first_of_adaptor(X&& x) 
0116     BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(F1, X&&)
0117     : F1(BOOST_HOF_FORWARD(X)(x))
0118     {} 
0119 
0120     template<class... Ts>
0121     struct select
0122     : std::conditional
0123     <
0124         is_invocable<F1, Ts...>::value, 
0125         F1,
0126         F2
0127     >
0128     {};
0129 
0130     BOOST_HOF_RETURNS_CLASS(basic_first_of_adaptor);
0131 
0132     template<class... Ts, class F=typename select<Ts...>::type>
0133     constexpr BOOST_HOF_SFINAE_RESULT(typename select<Ts...>::type, id_<Ts>...) 
0134     operator()(Ts && ... xs) const
0135     BOOST_HOF_SFINAE_RETURNS
0136     (
0137         BOOST_HOF_RETURNS_STATIC_CAST(const F&)(*BOOST_HOF_CONST_THIS)(BOOST_HOF_FORWARD(Ts)(xs)...)
0138     );
0139 };
0140 
0141 template <class F1, class F2>
0142 constexpr const F1& which(std::true_type, const F1& f1, const F2&) noexcept
0143 { 
0144     return f1; 
0145 }
0146 
0147 template <class F1, class F2>
0148 constexpr const F2& which(std::false_type, const F1&, const F2& f2) noexcept
0149 { 
0150     return f2; 
0151 }
0152 
0153 template<class F1, class F2>
0154 struct conditional_kernel : compressed_pair<F1, F2>
0155 {
0156     typedef compressed_pair<F1, F2> base;
0157     BOOST_HOF_INHERIT_CONSTRUCTOR(conditional_kernel, base)
0158 
0159     template<class... Ts>
0160     struct select
0161     : std::conditional
0162     <
0163         is_invocable<F1, Ts...>::value, 
0164         F1,
0165         F2
0166     >
0167     {};
0168 
0169     BOOST_HOF_RETURNS_CLASS(conditional_kernel);
0170 
0171     template<class... Ts, class PickFirst=is_invocable<F1, Ts...>>
0172     constexpr BOOST_HOF_SFINAE_RESULT(typename select<Ts...>::type, id_<Ts>...) 
0173     operator()(Ts && ... xs) const
0174     BOOST_HOF_SFINAE_RETURNS
0175     (
0176         boost::hof::detail::which(
0177             BOOST_HOF_RETURNS_CONSTRUCT(PickFirst)(),
0178             BOOST_HOF_MANGLE_CAST(const F1&)(BOOST_HOF_CONST_THIS->first(xs...)),
0179             BOOST_HOF_MANGLE_CAST(const F2&)(BOOST_HOF_CONST_THIS->second(xs...))
0180         )
0181         (BOOST_HOF_FORWARD(Ts)(xs)...)
0182     );
0183 };
0184 }
0185 
0186 template<class F, class... Fs>
0187 struct first_of_adaptor 
0188 : detail::conditional_kernel<F, BOOST_HOF_JOIN(first_of_adaptor, Fs...) >
0189 {
0190     typedef first_of_adaptor fit_rewritable_tag;
0191     typedef BOOST_HOF_JOIN(first_of_adaptor, Fs...) kernel_base;
0192     typedef detail::conditional_kernel<F, kernel_base > base;
0193 
0194     BOOST_HOF_INHERIT_DEFAULT(first_of_adaptor, base)
0195 
0196     template<class X, class... Xs, 
0197         BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base, X, kernel_base), 
0198         BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(kernel_base, Xs...)>
0199     constexpr first_of_adaptor(X&& f1, Xs&& ... fs) 
0200     noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X&&, kernel_base) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(kernel_base, Xs&&...))
0201     : base(BOOST_HOF_FORWARD(X)(f1), kernel_base(BOOST_HOF_FORWARD(Xs)(fs)...))
0202     {}
0203 
0204     template<class X, class... Xs, 
0205         BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base, X)>
0206     constexpr first_of_adaptor(X&& f1) 
0207     BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(base, X&&)
0208     : base(BOOST_HOF_FORWARD(X)(f1))
0209     {}
0210 
0211     struct failure
0212     : failure_for<F, Fs...>
0213     {};
0214 };
0215 
0216 template<class F>
0217 struct first_of_adaptor<F> : F
0218 {
0219     typedef first_of_adaptor fit_rewritable_tag;
0220     BOOST_HOF_INHERIT_CONSTRUCTOR(first_of_adaptor, F);
0221 
0222     struct failure
0223     : failure_for<F>
0224     {};
0225 };
0226 
0227 template<class F1, class F2>
0228 struct first_of_adaptor<F1, F2> 
0229 : detail::conditional_kernel<F1, F2>
0230 {
0231     typedef detail::conditional_kernel<F1, F2> base;
0232     typedef first_of_adaptor fit_rewritable_tag;
0233     BOOST_HOF_INHERIT_CONSTRUCTOR(first_of_adaptor, base);
0234 
0235     struct failure
0236     : failure_for<F1, F2>
0237     {};
0238 };
0239 
0240 BOOST_HOF_DECLARE_STATIC_VAR(first_of, detail::make<first_of_adaptor>);
0241 
0242 }} // namespace boost::hof
0243 
0244 #endif