Edit: /usr/include/boost/hof/reveal.hpp (12187B)
/*=============================================================================
Copyright (c) 2014 Paul Fultz II
reveal.h
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#ifndef BOOST_HOF_GUARD_FUNCTION_REVEAL_H
#define BOOST_HOF_GUARD_FUNCTION_REVEAL_H
/// reveal
/// ======
///
/// Description
/// -----------
///
/// The `reveal` function adaptor helps shows the error messages that get
/// masked on some compilers. Sometimes an error in a function that causes a
/// substitution failure, will remove the function from valid overloads. On
/// compilers without a backtrace for substitution failure, this will mask the
/// error inside the function. The `reveal` adaptor will expose these error
/// messages while still keeping the function SFINAE-friendly.
///
/// Sample
/// ------
///
/// If we take the `print` example from the quick start guide like this:
///
/// namespace adl {
///
/// using std::begin;
///
/// template
/// auto adl_begin(R&& r) BOOST_HOF_RETURNS(begin(r));
/// }
///
/// BOOST_HOF_STATIC_LAMBDA_FUNCTION(for_each_tuple) = [](const auto& sequence, auto f) BOOST_HOF_RETURNS
/// (
/// boost::hof::unpack(boost::hof::proj(f))(sequence)
/// );
///
/// auto print = boost::hof::fix(boost::hof::first_of(
/// [](auto, const auto& x) -> decltype(std::cout << x, void())
/// {
/// std::cout << x << std::endl;
/// },
/// [](auto self, const auto& range) -> decltype(self(*adl::adl_begin(range)), void())
/// {
/// for(const auto& x:range) self(x);
/// },
/// [](auto self, const auto& tuple) -> decltype(for_each_tuple(tuple, self), void())
/// {
/// return for_each_tuple(tuple, self);
/// }
/// ));
///
/// Which prints numbers and vectors:
///
/// print(5);
///
/// std::vector v = { 1, 2, 3, 4 };
/// print(v);
///
/// However, if we pass a type that can't be printed, we get an error like
/// this:
///
/// print.cpp:49:5: error: no matching function for call to object of type 'boost::hof::fix_adaptor >'
/// print(foo{});
/// ^~~~~
/// fix.hpp:158:5: note: candidate template ignored: substitution failure [with Ts = ]: no matching function for call to object of type 'const boost::hof::first_of_adaptor<(lambda at
/// print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>'
/// operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
///
/// Which is short and gives very little information why it can't be called.
/// It doesn't even show the overloads that were try. However, using the
/// `reveal` adaptor we can get more info about the error like this:
///
/// print.cpp:49:5: error: no matching function for call to object of type 'boost::hof::reveal_adaptor >, boost::hof::fix_adaptor > >'
/// boost::hof::reveal(print)(foo{});
/// ^~~~~~~~~~~~~~~~~~
/// reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = , $1 = void]: no matching function for call to object of type '(lambda at print.cpp:29:9)'
/// constexpr auto operator()(Ts&&... xs) const
/// ^
/// reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = , $1 = void]: no matching function for call to object of type '(lambda at print.cpp:33:9)'
/// constexpr auto operator()(Ts&&... xs) const
/// ^
/// reveal.hpp:149:20: note: candidate template ignored: substitution failure [with Ts = , $1 = void]: no matching function for call to object of type '(lambda at print.cpp:37:9)'
/// constexpr auto operator()(Ts&&... xs) const
/// ^
/// fix.hpp:158:5: note: candidate template ignored: substitution failure [with Ts = ]: no matching function for call to object of type 'const boost::hof::first_of_adaptor<(lambda at
/// print.cpp:29:9), (lambda at print.cpp:33:9), (lambda at print.cpp:37:9)>'
/// operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
///
/// So now the error has a note for each of the lambda overloads it tried. Of
/// course this can be improved even further by providing custom reporting of
/// failures.
///
/// Synopsis
/// --------
///
/// template
/// reveal_adaptor reveal(F f);
///
/// Requirements
/// ------------
///
/// F must be:
///
/// * [ConstInvocable](ConstInvocable)
/// * MoveConstructible
///
/// Reporting Failures
/// ------------------
///
/// By default, `reveal` reports the substitution failure by trying to call
/// the function. However, more detail expressions can be be reported from a
/// template alias by using `as_failure`. This is done by defining a nested
/// `failure` struct in the function object and then inheriting from
/// `as_failure`. Also multiple failures can be reported by using
/// `with_failures`.
///
/// Synopsis
/// --------
///
/// // Report failure by instantiating the Template
/// template class Template>
/// struct as_failure;
///
/// // Report multiple falures
/// template
/// struct with_failures;
///
/// // Report the failure for each function
/// template
/// struct failure_for;
///
/// // Get the failure of a function
/// template
/// struct get_failure;
///
/// Example
/// -------
///
/// #include
/// #include
///
/// struct sum_f
/// {
/// template
/// using sum_failure = decltype(std::declval()+std::declval());
///
/// struct failure
/// : boost::hof::as_failure
/// {};
///
/// template
/// auto operator()(T x, U y) const BOOST_HOF_RETURNS(x+y);
/// };
///
/// int main() {
/// assert(sum_f()(1, 2) == 3);
/// }
///
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
#ifdef __clang__
#define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 1
#else
#define BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS 0
#endif
#endif
namespace boost { namespace hof {
namespace detail {
template
struct has_failure
: std::false_type
{};
template
struct has_failure::type>
: std::true_type
{};
struct identity_failure
{
template
T operator()(T&& x);
template
static T&& val();
#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
template class Template, class... Ts>
BOOST_HOF_USING(defer, Template);
#else
template class Template, class... Ts>
static auto defer(Ts&&...) -> Template;
#endif
};
}
template
struct get_failure
{
template
struct of
{
#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
template
using apply = decltype(Id()(std::declval())(std::declval()...));
#else
template
static auto apply(Id id) -> decltype(id(std::declval())(std::declval()...));
#endif
};
};
template
struct get_failure::value>::type>
: F::failure
{};
template class Template>
struct as_failure
{
template
struct of
{
#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
template
using apply = typename Id::template defer;
#else
template
static auto apply(Id) -> decltype(Id::template defer());
#endif
};
};
namespace detail {
template
BOOST_HOF_USING_TYPENAME(apply_failure, Failure::template of);
template
struct reveal_failure
{
// Add default constructor to make clang 3.4 happy
constexpr reveal_failure()
{}
// This is just a placeholder to produce a note in the compiler, it is
// never called
template<
class... Ts,
class=typename std::enable_if<(!is_invocable::value)>::type
>
constexpr auto operator()(Ts&&... xs) const
#if BOOST_HOF_REVEAL_USE_TEMPLATE_ALIAS
-> typename apply_failure::template apply;
#else
-> decltype(apply_failure::apply(boost::hof::detail::identity_failure()));
#endif
};
template, class=void>
struct traverse_failure
: reveal_failure
{
constexpr traverse_failure()
{}
};
template
struct traverse_failure::type>
: Failure::children::template overloads
{
constexpr traverse_failure()
{}
};
template
struct transform_failures
: Transform::template apply
{};
template
struct transform_failures::type>
: Failure::children::template transform
{};
}
template
struct failures;
template
struct with_failures
{
typedef BOOST_HOF_JOIN(failures, Fs...) children;
};
template
struct failures
{
template
BOOST_HOF_USING(transform, with_failures, detail::transform_failures...>);
template
struct overloads
: detail::traverse_failure, FailureBase::template overloads
{
constexpr overloads()
{}
using detail::traverse_failure::operator();
using FailureBase::template overloads::operator();
};
};
template
struct failures
{
template
BOOST_HOF_USING(transform, with_failures>);
template
BOOST_HOF_USING(overloads, detail::traverse_failure);
};
template
struct failure_map
: with_failures, Transform>...>
{};
template
struct failure_for
: with_failures...>
{};
template>
struct reveal_adaptor
: detail::traverse_failure, Base
{
typedef reveal_adaptor fit_rewritable1_tag;
using detail::traverse_failure::operator();
using Base::operator();
BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, Base);
};
// Avoid double reveals, it causes problem on gcc 4.6
template
struct reveal_adaptor>
: reveal_adaptor
{
typedef reveal_adaptor fit_rewritable1_tag;
BOOST_HOF_INHERIT_CONSTRUCTOR(reveal_adaptor, reveal_adaptor);
};
BOOST_HOF_DECLARE_STATIC_VAR(reveal, detail::make);
}} // namespace boost::hof
#endif