#define BOOST_HISTOGRAM_DETAIL_DETECT_HPP
#include <boost/histogram/fwd.hpp>
-#include <boost/mp11/algorithm.hpp>
-#include <boost/mp11/function.hpp>
-#include <boost/mp11/utility.hpp>
+#include <boost/mp11/function.hpp> // mp_and, mp_or
+#include <boost/mp11/integral.hpp> // mp_not
+#include <boost/mp11/list.hpp> // mp_first
#include <iterator>
#include <tuple>
#include <type_traits>
namespace histogram {
namespace detail {
-#define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
- template <class T> \
- using name##_impl = decltype(cond); \
- template <class T> \
- using name = typename boost::mp11::mp_valid<name##_impl, T>::type
-
-#define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
- template <class T, class U> \
- using name##_impl = decltype(cond); \
- template <class T, class U = T> \
- using name = typename boost::mp11::mp_valid<name##_impl, T, U>::type
-
-// metadata has overloads, trying to get pmf in this case always fails
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_metadata, (std::declval<T&>().metadata()));
-
-// resize has overloads, trying to get pmf in this case always fails
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_resize, (std::declval<T&>().resize(0)));
-
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_size, &T::size);
-
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_clear, &T::clear);
-
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_lower, &T::lower);
-
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_value, &T::value);
-
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_update, &T::update);
+#define BOOST_HISTOGRAM_DETAIL_DETECT(name, cond) \
+ template <class U> \
+ struct name##_impl { \
+ typedef char yes[1]; \
+ typedef char no[2]; \
+ template <class T> \
+ static yes& test(T& t, decltype(cond, 0)); \
+ template <class T> \
+ static no& test(T&, float); \
+ using type = \
+ std::integral_constant<bool, (sizeof(test(std::declval<U&>(), 0)) == 1)>; \
+ }; \
+ template <class T> \
+ using name = typename name##_impl<T>::type
+
+#define BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(name, cond) \
+ template <class V, class W> \
+ struct name##_impl { \
+ typedef char yes[1]; \
+ typedef char no[2]; \
+ template <class T, class U> \
+ static yes& test(decltype(cond, 0)); \
+ template <class, class> \
+ static no& test(float); \
+ using type = std::integral_constant<bool, (sizeof(test<V, W>(0)) == 1)>; \
+ }; \
+ template <class T, class U = T> \
+ using name = typename name##_impl<T, U>::type
// reset has overloads, trying to get pmf in this case always fails
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, (std::declval<T>().reset(0)));
-
-BOOST_HISTOGRAM_DETAIL_DETECT(has_method_options, &T::options);
+BOOST_HISTOGRAM_DETAIL_DETECT(has_method_reset, t.reset(0));
-BOOST_HISTOGRAM_DETAIL_DETECT(has_allocator, &T::get_allocator);
-
-BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, (std::declval<T&>()[0]));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable, t[0]);
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
is_transform,
(std::declval<T&>().inverse(std::declval<T&>().forward(std::declval<U>()))));
-BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container, (std::declval<T>()[0], &T::size,
- std::begin(std::declval<T>()),
- std::end(std::declval<T>())));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_indexable_container,
+ (t[0], t.size(), std::begin(t), std::end(t)));
BOOST_HISTOGRAM_DETAIL_DETECT(is_vector_like,
- (std::declval<T>()[0], &T::size,
- std::declval<T>().resize(0), std::begin(std::declval<T>()),
- std::end(std::declval<T>())));
+ (t[0], t.size(), t.resize(0), std::begin(t), std::end(t)));
-BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like,
- (std::declval<T>()[0], &T::size, std::tuple_size<T>::value,
- std::begin(std::declval<T>()),
- std::end(std::declval<T>())));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_array_like, (t[0], t.size(), std::tuple_size<T>::value,
+ std::begin(t), std::end(t)));
-BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, (std::declval<typename T::key_type>(),
- std::declval<typename T::mapped_type>(),
- std::begin(std::declval<T>()),
- std::end(std::declval<T>())));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_map_like, ((typename T::key_type*)nullptr,
+ (typename T::mapped_type*)nullptr,
+ std::begin(t), std::end(t)));
// ok: is_axis is false for axis::variant, because T::index is templated
-BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (&T::size, &T::index));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_axis, (t.size(), &T::index));
-BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(std::declval<T&>()),
- std::end(std::declval<T&>())));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_iterable, (std::begin(t), std::end(t)));
BOOST_HISTOGRAM_DETAIL_DETECT(is_iterator,
- (typename std::iterator_traits<T>::iterator_category()));
+ (typename std::iterator_traits<T>::iterator_category{}));
-BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable,
- (std::declval<std::ostream&>() << std::declval<T&>()));
+BOOST_HISTOGRAM_DETAIL_DETECT(is_streamable, (std::declval<std::ostream&>() << t));
-BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, (++std::declval<T&>()));
+BOOST_HISTOGRAM_DETAIL_DETECT(has_operator_preincrement, ++t);
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_equal, (std::declval<const T&>() ==
- std::declval<const U>()));
+ std::declval<const U&>()));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(has_operator_radd,
(std::declval<T&>() += std::declval<U>()));
(std::declval<T&>() /= std::declval<U>()));
BOOST_HISTOGRAM_DETAIL_DETECT_BINARY(
- has_method_eq, (std::declval<const T>().operator==(std::declval<const U>())));
+ has_method_eq, (std::declval<const T&>().operator==(std::declval<const U&>())));
BOOST_HISTOGRAM_DETAIL_DETECT(has_threading_support, (T::has_threading_support));
mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>>;
template <class T>
-struct is_tuple_impl : mp11::mp_false {};
+struct is_tuple_impl : std::false_type {};
template <class... Ts>
-struct is_tuple_impl<std::tuple<Ts...>> : mp11::mp_true {};
+struct is_tuple_impl<std::tuple<Ts...>> : std::true_type {};
template <class T>
using is_tuple = typename is_tuple_impl<T>::type;
template <class T>
-struct is_variant_impl : mp11::mp_false {};
+struct is_variant_impl : std::false_type {};
template <class... Ts>
-struct is_variant_impl<boost::variant2::variant<Ts...>> : mp11::mp_true {};
+struct is_variant_impl<boost::variant2::variant<Ts...>> : std::true_type {};
template <class T>
using is_variant = typename is_variant_impl<T>::type;
template <class T>
-struct is_axis_variant_impl : mp11::mp_false {};
+struct is_axis_variant_impl : std::false_type {};
template <class... Ts>
-struct is_axis_variant_impl<axis::variant<Ts...>> : mp11::mp_true {};
+struct is_axis_variant_impl<axis::variant<Ts...>> : std::true_type {};
template <class T>
using is_axis_variant = typename is_axis_variant_impl<T>::type;
class = std::enable_if_t<is_any_axis<mp11::mp_first<std::decay_t<T>>>::value>>
struct requires_axes {};
-template <class T, class U, class = std::enable_if_t<std::is_convertible<T, U>::value>>
-struct requires_convertible {};
-
template <class T, class U,
class = std::enable_if_t<is_transform<std::decay_t<T>, U>::value>>
struct requires_transform {};