Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:43:52

0001 /*=============================================================================
0002     Copyright (c) 2014 Paul Fultz II
0003     reveal.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_REVEAL_H
0009 #define BOOST_HOF_GUARD_FUNCTION_REVEAL_H
0010 
0011 /// reveal
0012 /// ======
0013 /// 
0014 /// Description
0015 /// -----------
0016 /// 
0017 /// The `reveal` function adaptor helps shows the error messages that get
0018 /// masked on some compilers. Sometimes an error in a function that causes a
0019 /// substitution failure, will remove the function from valid overloads. On
0020 /// compilers without a backtrace for substitution failure, this will mask the
0021 /// error inside the function. The `reveal` adaptor will expose these error
0022 /// messages while still keeping the function SFINAE-friendly.
0023 /// 
0024 /// Sample
0025 /// ------
0026 /// 
0027 /// If we take the `print` example from the quick start guide like this:
0028 /// 
0029 ///     namespace adl {
0030 /// 
0031 ///     using std::begin;
0032 /// 
0033 ///     template<class R>
0034 ///     auto adl_begin(R&& r) BOOST_HOF_RETURNS(begin(r));
0035 ///     }
0036 /// 
0037 ///     BOOST_HOF_STATIC_LAMBDA_FUNCTION(for_each_tuple) = [](const auto& sequence, auto f) BOOST_HOF_RETURNS
0038 ///     (
0039 ///         boost::hof::unpack(boost::hof::proj(f))(sequence)
0040 ///     );
0041 /// 
0042 ///     auto print = boost::hof::fix(boost::hof::first_of(
0043 ///         [](auto, const auto& x) -> decltype(std::cout << x, void())
0044 ///         {
0045 ///             std::cout << x << std::endl;
0046 ///         },
0047 ///         [](auto self, const auto& range) -> decltype(self(*adl::adl_begin(range)), void())
0048 ///         {
0049 ///             for(const auto& x:range) self(x);
0050 ///         },
0051 ///         [](auto self, const auto& tuple) -> decltype(for_each_tuple(tuple, self), void())
0052 ///         {
0053 ///             return for_each_tuple(tuple, self);
0054 ///         }
0055 ///     ));
0056 /// 
0057 /// Which prints numbers and vectors:
0058 /// 
0059 ///     print(5);
0060 /// 
0061 ///     std::vector<int> v = { 1, 2, 3, 4 };
0062 ///     print(v);
0063 /// 
0064 /// However, if we pass a type that can't be printed, we get an error like
0065 /// this:
0066 /// 
0067 ///     print.cpp:49:5: error: no matching function for call to object of type 'boost::hof::fix_adaptor<boost::hof::first_of_adaptor<(lambda at print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)> >'
0068 ///         print(foo{});
0069 ///         ^~~~~
0070 ///     fix.hpp:158:5: note: candidate template ignored: substitution failure [with Ts = <foo>]: no matching function for call to object of type 'const boost::hof::first_of_adaptor<(lambda at
0071 ///           print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>'
0072 ///         operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
0073 /// 
0074 /// Which is short and gives very little information why it can't be called.
0075 /// It doesn't even show the overloads that were try. However, using the
0076 /// `reveal` adaptor we can get more info about the error like this:
0077 /// 
0078 ///     print.cpp:49:5: error: no matching function for call to object of type 'boost::hof::reveal_adaptor<boost::hof::fix_adaptor<boost::hof::first_of_adaptor<(lambda at print.cpp:29:9), (lambda at print.cpp:33:9),
0079 ///           (lambda at print.cpp:37:9)> >, boost::hof::fix_adaptor<boost::hof::first_of_adaptor<(lambda at print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)> > >'
0080 ///         boost::hof::reveal(print)(foo{});
0081 ///         ^~~~~~~~~~~~~~~~~~
0082 ///     reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = <foo>, $1 = void]: no matching function for call to object of type '(lambda at print.cpp:29:9)'
0083 ///         constexpr auto operator()(Ts&&... xs) const
0084 ///                        ^
0085 ///     reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = <foo>, $1 = void]: no matching function for call to object of type '(lambda at print.cpp:33:9)'
0086 ///         constexpr auto operator()(Ts&&... xs) const
0087 ///                        ^
0088 ///     reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = <foo>, $1 = void]: no matching function for call to object of type '(lambda at print.cpp:37:9)'
0089 ///         constexpr auto operator()(Ts&&... xs) const
0090 ///                        ^
0091 ///     fix.hpp:158:5: note: candidate template ignored: substitution failure [with Ts = <foo>]: no matching function for call to object of type 'const boost::hof::first_of_adaptor<(lambda at
0092 ///           print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>'
0093 ///         operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
0094 /// 
0095 /// So now the error has a note for each of the lambda overloads it tried. Of
0096 /// course this can be improved even further by providing custom reporting of
0097 /// failures.
0098 /// 
0099 /// Synopsis
0100 /// --------
0101 /// 
0102 ///     template<class F>
0103 ///     reveal_adaptor<F> reveal(F f);
0104 /// 
0105 /// Requirements
0106 /// ------------
0107 /// 
0108 /// F must be:
0109 /// 
0110 /// * [ConstInvocable](ConstInvocable)
0111 /// * MoveConstructible
0112 /// 
0113 /// Reporting Failures
0114 /// ------------------
0115 /// 
0116 /// By default, `reveal` reports the substitution failure by trying to call
0117 /// the function. However, more detail expressions can be be reported from a
0118 /// template alias by using `as_failure`. This is done by defining a nested
0119 /// `failure` struct in the function object and then inheriting from
0120 /// `as_failure`. Also multiple failures can be reported by using
0121 /// `with_failures`.
0122 /// 
0123 /// Synopsis
0124 /// --------
0125 /// 
0126 ///     // Report failure by instantiating the Template
0127 ///     template<template<class...> class Template>
0128 ///     struct as_failure;
0129 /// 
0130 ///     // Report multiple falures
0131 ///     template<class... Failures>
0132 ///     struct with_failures;
0133 /// 
0134 ///     // Report the failure for each function
0135 ///     template<class... Fs>
0136 ///     struct failure_for;
0137 /// 
0138 ///     // Get the failure of a function
0139 ///     template<class F>
0140 ///     struct get_failure;
0141 /// 
0142 /// Example
0143 /// -------
0144 /// 
0145 ///     #include <boost/hof.hpp>
0146 ///     #include <cassert>
0147 /// 
0148 ///     struct sum_f
0149 ///     {
0150 ///         template<class T, class U>
0151 ///         using sum_failure = decltype(std::declval<T>()+std::declval<U>());
0152 /// 
0153 ///         struct failure
0154 ///         : boost::hof::as_failure<sum_failure>
0155 ///         {};
0156 /// 
0157 ///         template<class T, class U>
0158 ///         auto operator()(T x, U y) const BOOST_HOF_RETURNS(x+y);
0159 ///     };
0160 /// 
0161 ///     int main() {
0162 ///         assert(sum_f()(1, 2) == 3);
0163 ///     }
0164 /// 
0165 
0166 #include <boost/hof/always.hpp>
0167 #include <boost/hof/returns.hpp>
0168 #include <boost/hof/is_invocable.hpp>
0169 #include <boost/hof/identity.hpp>
0170 #include <boost/hof/detail/move.hpp>
0171 #include <boost/hof/detail/callable_base.hpp>
0172 #include <boost/hof/detail/delegate.hpp>
0173 #include <boost/hof/detail/holder.hpp>
0174 #include <boost/hof/detail/join.hpp>
0175 #include <boost/hof/detail/make.hpp>
0176 #include <boost/hof/detail/static_const_var.hpp>
0177 #include <boost/hof/detail/using.hpp>
0178 
0179 #ifndef BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
0180 #ifdef __clang__
0181 #define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 1
0182 #else
0183 #define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 0
0184 #endif
0185 #endif
0186 
0187 namespace boost { namespace hof { 
0188 
0189 namespace detail {
0190 
0191 
0192 template<class T, class=void>
0193 struct has_failure
0194 : std::false_type
0195 {};
0196 
0197 template<class T>
0198 struct has_failure<T, typename holder<
0199     typename T::failure
0200 >::type>
0201 : std::true_type
0202 {};
0203 
0204 struct identity_failure
0205 {
0206     template<class T>
0207     T operator()(T&& x);
0208 
0209     template<class T>
0210     static T&& val();
0211 #if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
0212     template<template<class...> class Template, class... Ts>
0213     BOOST_HOF_USING(defer, Template<Ts...>);
0214 #else
0215     template<template<class...> class Template, class... Ts>
0216     static auto defer(Ts&&...) -> Template<Ts...>;
0217 #endif
0218 
0219 };
0220 
0221 }
0222 
0223 template<class F, class=void>
0224 struct get_failure
0225 {
0226     template<class... Ts>
0227     struct of
0228     {
0229 #if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
0230         template<class Id>
0231         using apply = decltype(Id()(std::declval<F>())(std::declval<Ts>()...));
0232 #else
0233         template<class Id>
0234         static auto apply(Id id) -> decltype(id(std::declval<F>())(std::declval<Ts>()...));
0235 #endif
0236     };
0237 };
0238 
0239 template<class F>
0240 struct get_failure<F, typename std::enable_if<detail::has_failure<F>::value>::type>
0241 : F::failure
0242 {};
0243 
0244 template<template<class...> class Template>
0245 struct as_failure
0246 {
0247     template<class... Ts>
0248     struct of
0249     {
0250 #if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
0251         template<class Id>
0252         using apply = typename Id::template defer<Template, Ts...>;
0253 #else
0254         template<class Id>
0255         static auto apply(Id) -> decltype(Id::template defer<Template, Ts...>());
0256 #endif
0257     };
0258 };
0259 
0260 namespace detail {
0261 template<class Failure, class... Ts>
0262 BOOST_HOF_USING_TYPENAME(apply_failure, Failure::template of<Ts...>);
0263 
0264 template<class F, class Failure>
0265 struct reveal_failure
0266 {
0267     // Add default constructor to make clang 3.4 happy
0268     constexpr reveal_failure()
0269     {}
0270     // This is just a placeholder to produce a note in the compiler, it is
0271     // never called
0272     template<
0273         class... Ts, 
0274         class=typename std::enable_if<(!is_invocable<F, Ts...>::value)>::type
0275     >
0276     constexpr auto operator()(Ts&&... xs) const
0277 #if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
0278         -> typename apply_failure<Failure, Ts...>::template apply<boost::hof::detail::identity_failure>;
0279 #else
0280         -> decltype(apply_failure<Failure, Ts...>::apply(boost::hof::detail::identity_failure()));
0281 #endif
0282 };
0283 
0284 template<class F, class Failure=get_failure<F>, class=void>
0285 struct traverse_failure 
0286 : reveal_failure<F, Failure>
0287 {
0288     constexpr traverse_failure()
0289     {}
0290 };
0291 
0292 template<class F, class Failure>
0293 struct traverse_failure<F, Failure, typename holder< 
0294     typename Failure::children
0295 >::type> 
0296 : Failure::children::template overloads<F>
0297 {
0298     constexpr traverse_failure()
0299     {}
0300 };
0301 
0302 template<class Failure, class Transform, class=void>
0303 struct transform_failures 
0304 : Transform::template apply<Failure>
0305 {};
0306 
0307 template<class Failure, class Transform>
0308 struct transform_failures<Failure, Transform, typename holder< 
0309     typename Failure::children
0310 >::type> 
0311 : Failure::children::template transform<Transform>
0312 {};
0313 
0314 }
0315 
0316 template<class Failure, class... Failures>
0317 struct failures;
0318 
0319 template<class... Fs>
0320 struct with_failures
0321 {
0322     typedef BOOST_HOF_JOIN(failures, Fs...) children;
0323 };
0324 
0325 template<class Failure, class... Failures>
0326 struct failures 
0327 {
0328     template<class Transform>
0329     BOOST_HOF_USING(transform, with_failures<detail::transform_failures<Failure, Transform>, detail::transform_failures<Failures, Transform>...>);
0330 
0331     template<class F, class FailureBase=BOOST_HOF_JOIN(failures, Failures...)>
0332     struct overloads
0333     : detail::traverse_failure<F, Failure>, FailureBase::template overloads<F>
0334     {
0335         constexpr overloads()
0336         {}
0337         using detail::traverse_failure<F, Failure>::operator();
0338         using FailureBase::template overloads<F>::operator();
0339     };
0340 };
0341 
0342 template<class Failure>
0343 struct failures<Failure>
0344 {
0345     template<class Transform>
0346     BOOST_HOF_USING(transform, with_failures<detail::transform_failures<Failure, Transform>>);
0347 
0348     template<class F>
0349     BOOST_HOF_USING(overloads, detail::traverse_failure<F, Failure>);
0350 };
0351 
0352 template<class Transform, class... Fs>
0353 struct failure_map
0354 : with_failures<detail::transform_failures<get_failure<Fs>, Transform>...>
0355 {};
0356 
0357 template<class... Fs>
0358 struct failure_for
0359 : with_failures<get_failure<Fs>...>
0360 {};
0361 
0362 template<class F, class Base=detail::callable_base<F>>
0363 struct reveal_adaptor
0364 : detail::traverse_failure<Base>, Base
0365 {
0366     typedef reveal_adaptor fit_rewritable1_tag;
0367     using detail::traverse_failure<Base>::operator();
0368     using Base::operator();
0369 
0370     BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, Base);
0371 };
0372 // Avoid double reveals, it causes problem on gcc 4.6
0373 template<class F>
0374 struct reveal_adaptor<reveal_adaptor<F>>
0375 : reveal_adaptor<F>
0376 {
0377     typedef reveal_adaptor fit_rewritable1_tag;
0378     BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, reveal_adaptor<F>);
0379 };
0380 
0381 BOOST_HOF_DECLARE_STATIC_VAR(reveal, detail::make<reveal_adaptor>);
0382 
0383 }} // namespace boost::hof
0384 
0385 #endif