accumulator_traits.hpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // Copyright 2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_DETAIL_ACCUMULATOR_TRAITS_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_ACCUMULATOR_TRAITS_HPP
  8. #include <boost/histogram/detail/priority.hpp>
  9. #include <boost/histogram/fwd.hpp>
  10. #include <tuple>
  11. #include <type_traits>
  12. namespace boost {
  13. // forward declare accumulator_set so that it can be matched below
  14. namespace accumulators {
  15. template <class, class, class>
  16. struct accumulator_set;
  17. }
  18. namespace histogram {
  19. namespace detail {
  20. template <bool WeightSupport, class... Ts>
  21. struct accumulator_traits_holder {
  22. static constexpr bool weight_support = WeightSupport;
  23. using args = std::tuple<Ts...>;
  24. };
  25. // member function pointer with weight_type as first argument is better match
  26. template <class R, class T, class U, class... Ts>
  27. accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
  28. R (T::*)(boost::histogram::weight_type<U>, Ts...));
  29. template <class R, class T, class U, class... Ts>
  30. accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
  31. R (T::*)(boost::histogram::weight_type<U>&, Ts...));
  32. template <class R, class T, class U, class... Ts>
  33. accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
  34. R (T::*)(boost::histogram::weight_type<U>&&, Ts...));
  35. template <class R, class T, class U, class... Ts>
  36. accumulator_traits_holder<true, Ts...> accumulator_traits_impl_call_op(
  37. R (T::*)(const boost::histogram::weight_type<U>&, Ts...));
  38. // member function pointer only considered if all specializations above fail
  39. template <class R, class T, class... Ts>
  40. accumulator_traits_holder<false, Ts...> accumulator_traits_impl_call_op(R (T::*)(Ts...));
  41. template <class T>
  42. auto accumulator_traits_impl(T&, priority<2>)
  43. -> decltype(accumulator_traits_impl_call_op(&T::operator()));
  44. template <class T>
  45. auto accumulator_traits_impl(T&, priority<2>)
  46. -> decltype(std::declval<T&>() += std::declval<boost::histogram::weight_type<int>>(),
  47. accumulator_traits_holder<true>{});
  48. // fallback for simple arithmetic types that do not implement adding a weight_type
  49. template <class T>
  50. auto accumulator_traits_impl(T&, priority<1>)
  51. -> decltype(std::declval<T&>() += 0, accumulator_traits_holder<true>{});
  52. template <class T>
  53. auto accumulator_traits_impl(T&, priority<0>) -> accumulator_traits_holder<false>;
  54. // for boost.accumulators compatibility
  55. template <class S, class F, class W>
  56. accumulator_traits_holder<false, S> accumulator_traits_impl(
  57. boost::accumulators::accumulator_set<S, F, W>&, priority<2>) {
  58. static_assert(std::is_same<W, void>::value,
  59. "accumulator_set with weights is not directly supported, please use "
  60. "a wrapper class that implements the Accumulator concept");
  61. }
  62. template <class T>
  63. using accumulator_traits =
  64. decltype(accumulator_traits_impl(std::declval<T&>(), priority<2>{}));
  65. } // namespace detail
  66. } // namespace histogram
  67. } // namespace boost
  68. #endif