1/*=============================================================================
2 Copyright (c) 2014 Paul Fultz II
3 reveal.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_REVEAL_H
9#define BOOST_HOF_GUARD_FUNCTION_REVEAL_H
10
11/// reveal
12/// ======
13///
14/// Description
15/// -----------
16///
17/// The `reveal` function adaptor helps shows the error messages that get
18/// masked on some compilers. Sometimes an error in a function that causes a
19/// substitution failure, will remove the function from valid overloads. On
20/// compilers without a backtrace for substitution failure, this will mask the
21/// error inside the function. The `reveal` adaptor will expose these error
22/// messages while still keeping the function SFINAE-friendly.
23///
24/// Sample
25/// ------
26///
27/// If we take the `print` example from the quick start guide like this:
28///
29/// namespace adl {
30///
31/// using std::begin;
32///
33/// template<class R>
34/// auto adl_begin(R&& r) BOOST_HOF_RETURNS(begin(r));
35/// }
36///
37/// BOOST_HOF_STATIC_LAMBDA_FUNCTION(for_each_tuple) = [](const auto& sequence, auto f) BOOST_HOF_RETURNS
38/// (
39/// boost::hof::unpack(boost::hof::proj(f))(sequence)
40/// );
41///
42/// auto print = boost::hof::fix(boost::hof::first_of(
43/// [](auto, const auto& x) -> decltype(std::cout << x, void())
44/// {
45/// std::cout << x << std::endl;
46/// },
47/// [](auto self, const auto& range) -> decltype(self(*adl::adl_begin(range)), void())
48/// {
49/// for(const auto& x:range) self(x);
50/// },
51/// [](auto self, const auto& tuple) -> decltype(for_each_tuple(tuple, self), void())
52/// {
53/// return for_each_tuple(tuple, self);
54/// }
55/// ));
56///
57/// Which prints numbers and vectors:
58///
59/// print(5);
60///
61/// std::vector<int> v = { 1, 2, 3, 4 };
62/// print(v);
63///
64/// However, if we pass a type that can't be printed, we get an error like
65/// this:
66///
67/// 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)> >'
68/// print(foo{});
69/// ^~~~~
70/// 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
71/// print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>'
72/// operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
73///
74/// Which is short and gives very little information why it can't be called.
75/// It doesn't even show the overloads that were try. However, using the
76/// `reveal` adaptor we can get more info about the error like this:
77///
78/// 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),
79/// (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)> > >'
80/// boost::hof::reveal(print)(foo{});
81/// ^~~~~~~~~~~~~~~~~~
82/// 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)'
83/// constexpr auto operator()(Ts&&... xs) const
84/// ^
85/// 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)'
86/// constexpr auto operator()(Ts&&... xs) const
87/// ^
88/// 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)'
89/// constexpr auto operator()(Ts&&... xs) const
90/// ^
91/// 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
92/// print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>'
93/// operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
94///
95/// So now the error has a note for each of the lambda overloads it tried. Of
96/// course this can be improved even further by providing custom reporting of
97/// failures.
98///
99/// Synopsis
100/// --------
101///
102/// template<class F>
103/// reveal_adaptor<F> reveal(F f);
104///
105/// Requirements
106/// ------------
107///
108/// F must be:
109///
110/// * [ConstInvocable](ConstInvocable)
111/// * MoveConstructible
112///
113/// Reporting Failures
114/// ------------------
115///
116/// By default, `reveal` reports the substitution failure by trying to call
117/// the function. However, more detail expressions can be be reported from a
118/// template alias by using `as_failure`. This is done by defining a nested
119/// `failure` struct in the function object and then inheriting from
120/// `as_failure`. Also multiple failures can be reported by using
121/// `with_failures`.
122///
123/// Synopsis
124/// --------
125///
126/// // Report failure by instantiating the Template
127/// template<template<class...> class Template>
128/// struct as_failure;
129///
130/// // Report multiple falures
131/// template<class... Failures>
132/// struct with_failures;
133///
134/// // Report the failure for each function
135/// template<class... Fs>
136/// struct failure_for;
137///
138/// // Get the failure of a function
139/// template<class F>
140/// struct get_failure;
141///
142/// Example
143/// -------
144///
145/// #include <boost/hof.hpp>
146/// #include <cassert>
147///
148/// struct sum_f
149/// {
150/// template<class T, class U>
151/// using sum_failure = decltype(std::declval<T>()+std::declval<U>());
152///
153/// struct failure
154/// : boost::hof::as_failure<sum_failure>
155/// {};
156///
157/// template<class T, class U>
158/// auto operator()(T x, U y) const BOOST_HOF_RETURNS(x+y);
159/// };
160///
161/// int main() {
162/// assert(sum_f()(1, 2) == 3);
163/// }
164///
165
166#include <boost/hof/always.hpp>
167#include <boost/hof/returns.hpp>
168#include <boost/hof/is_invocable.hpp>
169#include <boost/hof/identity.hpp>
170#include <boost/hof/detail/move.hpp>
171#include <boost/hof/detail/callable_base.hpp>
172#include <boost/hof/detail/delegate.hpp>
173#include <boost/hof/detail/holder.hpp>
174#include <boost/hof/detail/join.hpp>
175#include <boost/hof/detail/make.hpp>
176#include <boost/hof/detail/static_const_var.hpp>
177#include <boost/hof/detail/using.hpp>
178
179#ifndef BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
180#ifdef __clang__
181#define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 1
182#else
183#define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 0
184#endif
185#endif
186
187namespace boost { namespace hof {
188
189namespace detail {
190
191
192template<class T, class=void>
193struct has_failure
194: std::false_type
195{};
196
197template<class T>
198struct has_failure<T, typename holder<
199 typename T::failure
200>::type>
201: std::true_type
202{};
203
204struct identity_failure
205{
206 template<class T>
207 T operator()(T&& x);
208
209 template<class T>
210 static T&& val();
211#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
212 template<template<class...> class Template, class... Ts>
213 BOOST_HOF_USING(defer, Template<Ts...>);
214#else
215 template<template<class...> class Template, class... Ts>
216 static auto defer(Ts&&...) -> Template<Ts...>;
217#endif
218
219};
220
221}
222
223template<class F, class=void>
224struct get_failure
225{
226 template<class... Ts>
227 struct of
228 {
229#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
230 template<class Id>
231 using apply = decltype(Id()(std::declval<F>())(std::declval<Ts>()...));
232#else
233 template<class Id>
234 static auto apply(Id id) -> decltype(id(std::declval<F>())(std::declval<Ts>()...));
235#endif
236 };
237};
238
239template<class F>
240struct get_failure<F, typename std::enable_if<detail::has_failure<F>::value>::type>
241: F::failure
242{};
243
244template<template<class...> class Template>
245struct as_failure
246{
247 template<class... Ts>
248 struct of
249 {
250#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
251 template<class Id>
252 using apply = typename Id::template defer<Template, Ts...>;
253#else
254 template<class Id>
255 static auto apply(Id) -> decltype(Id::template defer<Template, Ts...>());
256#endif
257 };
258};
259
260namespace detail {
261template<class Failure, class... Ts>
262BOOST_HOF_USING_TYPENAME(apply_failure, Failure::template of<Ts...>);
263
264template<class F, class Failure>
265struct reveal_failure
266{
267 // Add default constructor to make clang 3.4 happy
268 constexpr reveal_failure()
269 {}
270 // This is just a placeholder to produce a note in the compiler, it is
271 // never called
272 template<
273 class... Ts,
274 class=typename std::enable_if<(!is_invocable<F, Ts...>::value)>::type
275 >
276 constexpr auto operator()(Ts&&... xs) const
277#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
278 -> typename apply_failure<Failure, Ts...>::template apply<boost::hof::detail::identity_failure>;
279#else
280 -> decltype(apply_failure<Failure, Ts...>::apply(boost::hof::detail::identity_failure()));
281#endif
282};
283
284template<class F, class Failure=get_failure<F>, class=void>
285struct traverse_failure
286: reveal_failure<F, Failure>
287{
288 constexpr traverse_failure()
289 {}
290};
291
292template<class F, class Failure>
293struct traverse_failure<F, Failure, typename holder<
294 typename Failure::children
295>::type>
296: Failure::children::template overloads<F>
297{
298 constexpr traverse_failure()
299 {}
300};
301
302template<class Failure, class Transform, class=void>
303struct transform_failures
304: Transform::template apply<Failure>
305{};
306
307template<class Failure, class Transform>
308struct transform_failures<Failure, Transform, typename holder<
309 typename Failure::children
310>::type>
311: Failure::children::template transform<Transform>
312{};
313
314}
315
316template<class Failure, class... Failures>
317struct failures;
318
319template<class... Fs>
320struct with_failures
321{
322 typedef BOOST_HOF_JOIN(failures, Fs...) children;
323};
324
325template<class Failure, class... Failures>
326struct failures
327{
328 template<class Transform>
329 BOOST_HOF_USING(transform, with_failures<detail::transform_failures<Failure, Transform>, detail::transform_failures<Failures, Transform>...>);
330
331 template<class F, class FailureBase=BOOST_HOF_JOIN(failures, Failures...)>
332 struct overloads
333 : detail::traverse_failure<F, Failure>, FailureBase::template overloads<F>
334 {
335 constexpr overloads()
336 {}
337 using detail::traverse_failure<F, Failure>::operator();
338 using FailureBase::template overloads<F>::operator();
339 };
340};
341
342template<class Failure>
343struct failures<Failure>
344{
345 template<class Transform>
346 BOOST_HOF_USING(transform, with_failures<detail::transform_failures<Failure, Transform>>);
347
348 template<class F>
349 BOOST_HOF_USING(overloads, detail::traverse_failure<F, Failure>);
350};
351
352template<class Transform, class... Fs>
353struct failure_map
354: with_failures<detail::transform_failures<get_failure<Fs>, Transform>...>
355{};
356
357template<class... Fs>
358struct failure_for
359: with_failures<get_failure<Fs>...>
360{};
361
362template<class F, class Base=detail::callable_base<F>>
363struct reveal_adaptor
364: detail::traverse_failure<Base>, Base
365{
366 typedef reveal_adaptor fit_rewritable1_tag;
367 using detail::traverse_failure<Base>::operator();
368 using Base::operator();
369
370 BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, Base);
371};
372// Avoid double reveals, it causes problem on gcc 4.6
373template<class F>
374struct reveal_adaptor<reveal_adaptor<F>>
375: reveal_adaptor<F>
376{
377 typedef reveal_adaptor fit_rewritable1_tag;
378 BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, reveal_adaptor<F>);
379};
380
381BOOST_HOF_DECLARE_STATIC_VAR(reveal, detail::make<reveal_adaptor>);
382
383}} // namespace boost::hof
384
385#endif
386

source code of boost/libs/hof/include/boost/hof/reveal.hpp