use std::enable_if_t for check, to get better error messages

This commit is contained in:
Hans Dembinski
2019-01-24 21:35:17 +01:00
parent f7d083a49b
commit ed5af698bc
4 changed files with 41 additions and 39 deletions

View File

@@ -201,6 +201,9 @@ BOOST_HISTOGRAM_DETECT(is_axis, (&T::size, &T::operator()));
BOOST_HISTOGRAM_DETECT(is_iterable,
(std::begin(std::declval<T&>()), std::end(std::declval<T&>())));
BOOST_HISTOGRAM_DETECT(is_iterator,
(typename std::iterator_traits<T>::iterator_category()));
BOOST_HISTOGRAM_DETECT(is_streamable,
(std::declval<std::ostream&>() << std::declval<T&>()));
@@ -269,34 +272,31 @@ template <typename T>
using is_sample = is_sample_impl<naked<T>>;
// poor-mans concept checks
template <class B>
using requires = std::enable_if_t<B::value>;
template <class T, class = decltype(*std::declval<T&>(), ++std::declval<T&>())>
template <class T, class = std::enable_if_t<is_iterator<naked<T>>::value>>
struct requires_iterator {};
template <class T, class = requires<is_iterable<naked<T>>>>
template <class T, class = std::enable_if_t<is_iterable<naked<T>>::value>>
struct requires_iterable {};
template <class T, class = requires<is_axis<naked<T>>>>
template <class T, class = std::enable_if_t<is_axis<naked<T>>::value>>
struct requires_axis {};
template <class T, class = requires<is_any_axis<naked<T>>>>
template <class T, class = std::enable_if_t<is_any_axis<naked<T>>::value>>
struct requires_any_axis {};
template <class T, class = requires<is_sequence_of_axis<naked<T>>>>
template <class T, class = std::enable_if_t<is_sequence_of_axis<naked<T>>::value>>
struct requires_sequence_of_axis {};
template <class T, class = requires<is_sequence_of_axis_variant<naked<T>>>>
template <class T, class = std::enable_if_t<is_sequence_of_axis_variant<naked<T>>::value>>
struct requires_sequence_of_axis_variant {};
template <class T, class = requires<is_sequence_of_any_axis<naked<T>>>>
template <class T, class = std::enable_if_t<is_sequence_of_any_axis<naked<T>>::value>>
struct requires_sequence_of_any_axis {};
template <class T, class = requires<is_any_axis<mp11::mp_first<naked<T>>>>>
template <class T, class = std::enable_if_t<is_any_axis<mp11::mp_first<naked<T>>>::value>>
struct requires_axes {};
template <class T, class U, class = requires<std::is_convertible<T, U>>>
template <class T, class U, class = std::enable_if_t<std::is_convertible<T, U>::value>>
struct requires_convertible {};
template <class T>

View File

@@ -26,17 +26,17 @@ namespace histogram {
/**
Make histogram from compile-time axis configuration and custom storage.
@param s Storage or container with standard interface (any vector, array, or map).
@param storage Storage or container with standard interface (any vector, array, or map).
@param axis First axis instance.
@param axes Other axis instances.
*/
template <typename StorageOrContainer, typename T, typename... Ts,
template <typename Storage, typename T, typename... Ts,
typename = detail::requires_axis<T>>
auto make_histogram_with(StorageOrContainer&& s, T&& axis, Ts&&... axes) {
auto make_histogram_with(Storage&& storage, T&& axis, Ts&&... axes) {
auto a = std::make_tuple(std::forward<T>(axis), std::forward<Ts>(axes)...);
using U = detail::naked<StorageOrContainer>;
using U = detail::naked<Storage>;
using S = mp11::mp_if<detail::is_storage<U>, U, storage_adaptor<U>>;
return histogram<decltype(a), S>(std::move(a), S(std::forward<StorageOrContainer>(s)));
return histogram<decltype(a), S>(std::move(a), S(std::forward<Storage>(storage)));
}
/**
@@ -63,50 +63,50 @@ auto make_weighted_histogram(T&& axis, Ts&&... axes) {
/**
Make histogram from iterable range and custom storage.
@param s Storage or container with standard interface (any vector, array, or map).
@param c Iterable range of axis objects.
@param storage Storage or container with standard interface (any vector, array, or map).
@param iterable Iterable range of axis objects.
*/
template <typename StorageOrContainer, typename Iterable,
template <typename Storage, typename Iterable,
typename = detail::requires_sequence_of_any_axis<Iterable>>
auto make_histogram_with(StorageOrContainer&& s, Iterable&& c) {
using U = detail::naked<StorageOrContainer>;
auto make_histogram_with(Storage&& storage, Iterable&& iterable) {
using U = detail::naked<Storage>;
using S = mp11::mp_if<detail::is_storage<U>, U, storage_adaptor<U>>;
using It = detail::naked<Iterable>;
using A = mp11::mp_if<detail::is_indexable_container<It>, It,
boost::container::vector<mp11::mp_first<It>>>;
return histogram<A, S>(std::forward<Iterable>(c),
S(std::forward<StorageOrContainer>(s)));
return histogram<A, S>(std::forward<Iterable>(iterable),
S(std::forward<Storage>(storage)));
}
/**
Make histogram from iterable range and default storage.
@param c Iterable range of axis objects.
@param iterable Iterable range of axis objects.
*/
template <typename Iterable, typename = detail::requires_sequence_of_any_axis<Iterable>>
auto make_histogram(Iterable&& c) {
return make_histogram_with(default_storage(), std::forward<Iterable>(c));
auto make_histogram(Iterable&& iterable) {
return make_histogram_with(default_storage(), std::forward<Iterable>(iterable));
}
/**
Make histogram from iterable range and weight-counting storage.
@param c Iterable range of axis objects.
@param iterable Iterable range of axis objects.
*/
template <typename Iterable, typename = detail::requires_sequence_of_any_axis<Iterable>>
auto make_weighted_histogram(Iterable&& c) {
return make_histogram_with(weight_storage(), std::forward<Iterable>(c));
auto make_weighted_histogram(Iterable&& iterable) {
return make_histogram_with(weight_storage(), std::forward<Iterable>(iterable));
}
/**
Make histogram from iterator interval and custom storage.
@param s Storage or container with standard interface (any vector, array, or map).
@param storage Storage or container with standard interface (any vector, array, or map).
@param begin Iterator to range of axis objects.
@param end Iterator to range of axis objects.
*/
template <typename StorageOrContainer, typename Iterator,
template <typename Storage, typename Iterator,
typename = detail::requires_iterator<Iterator>>
auto make_histogram_with(StorageOrContainer&& s, Iterator begin, Iterator end) {
auto make_histogram_with(Storage&& storage, Iterator begin, Iterator end) {
using T = detail::naked<decltype(*begin)>;
return make_histogram_with(std::forward<StorageOrContainer>(s),
return make_histogram_with(std::forward<Storage>(storage),
boost::container::vector<T>(begin, end));
}

View File

@@ -122,7 +122,8 @@ struct map_impl : T {
return *this;
}
template <class U, class V = value_type, class = requires<has_operator_radd<V, U>>>
template <class U, class V = value_type,
class = std::enable_if_t<has_operator_radd<V, U>::value>>
reference& operator+=(U&& u) {
auto it = map->find(idx);
if (it != static_cast<T*>(map)->end())
@@ -132,7 +133,8 @@ struct map_impl : T {
return *this;
}
template <class V = value_type, class = requires<has_operator_preincrement<V>>>
template <class V = value_type,
class = std::enable_if_t<has_operator_preincrement<V>::value>>
reference& operator++() {
auto it = map->find(idx);
if (it != static_cast<T*>(map)->end())
@@ -147,7 +149,7 @@ struct map_impl : T {
return map->operator[](idx)(std::forward<Ts>(args)...);
}
template <class V = value_type, class = requires<has_operator_rmul<V>>>
template <class V = value_type, class = std::enable_if_t<has_operator_rmul<V>::value>>
reference& operator*=(double x) {
auto it = map->find(idx);
if (it != static_cast<T*>(map)->end()) it->second *= x;
@@ -264,7 +266,7 @@ public:
}
template <class V = typename base_type::value_type,
class = detail::requires<detail::has_operator_rmul<V>>>
class = std::enable_if_t<detail::has_operator_rmul<V>::value>>
storage_adaptor& operator*=(double v) {
for (auto&& x : *this) x *= v;
return *this;