cpp17: set axis compile-time options via deduction guide (#340)

This commit is contained in:
Hans Dembinski 2021-09-30 13:49:22 +02:00 committed by Hans Dembinski
parent 8f3a3c07e4
commit b482598597
6 changed files with 180 additions and 83 deletions

View File

@ -40,7 +40,7 @@ class boolean : public iterator_mixin<boolean<MetaData>>,
public: public:
/** Construct a boolean axis. /** Construct a boolean axis.
* *
* \param meta description of the axis. * @param meta description of the axis.
*/ */
explicit boolean(metadata_type meta = {}) : metadata_base(std::move(meta)) {} explicit boolean(metadata_type meta = {}) : metadata_base(std::move(meta)) {}

View File

@ -67,14 +67,17 @@ public:
/** Construct from iterator range of unique values. /** Construct from iterator range of unique values.
* *
* \param begin begin of category range of unique values. * @param begin begin of category range of unique values.
* \param end end of category range of unique values. * @param end end of category range of unique values.
* \param meta description of the axis. * @param meta description of the axis (optional).
* \param alloc allocator instance to use. * @param options see boost::histogram::axis::option (optional).
* @param alloc allocator instance to use (optional).
*/ */
template <class It, class = detail::requires_iterator<It>> template <class It, class = detail::requires_iterator<It>>
category(It begin, It end, metadata_type meta = {}, allocator_type alloc = {}) category(It begin, It end, metadata_type meta = {}, options_type options = {},
allocator_type alloc = {})
: metadata_base(std::move(meta)), vec_(alloc) { : metadata_base(std::move(meta)), vec_(alloc) {
(void)options;
if (std::distance(begin, end) < 0) if (std::distance(begin, end) < 0)
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
std::invalid_argument("end must be reachable by incrementing begin")); std::invalid_argument("end must be reachable by incrementing begin"));
@ -82,32 +85,51 @@ public:
while (begin != end) vec_.emplace_back(*begin++); while (begin != end) vec_.emplace_back(*begin++);
} }
// kept for backward compatibility
template <class It, class = detail::requires_iterator<It>>
category(It begin, It end, metadata_type meta, allocator_type alloc)
: category(begin, end, std::move(meta), {}, std::move(alloc)) {}
/** Construct axis from iterable sequence of unique values. /** Construct axis from iterable sequence of unique values.
* *
* \param iterable sequence of unique values. * @param iterable sequence of unique values.
* \param meta description of the axis. * @param meta description of the axis.
* \param alloc allocator instance to use. * @param options see boost::histogram::axis::option (optional).
* @param alloc allocator instance to use.
*/ */
template <class C, class = detail::requires_iterable<C>> template <class C, class = detail::requires_iterable<C>>
category(const C& iterable, metadata_type meta = {}, allocator_type alloc = {}) category(const C& iterable, metadata_type meta = {}, options_type options = {},
: category(std::begin(iterable), std::end(iterable), std::move(meta), allocator_type alloc = {})
: category(std::begin(iterable), std::end(iterable), std::move(meta), options,
std::move(alloc)) {}
// kept for backward compatibility
template <class C, class = detail::requires_iterable<C>>
category(const C& iterable, metadata_type meta, allocator_type alloc)
: category(std::begin(iterable), std::end(iterable), std::move(meta), {},
std::move(alloc)) {} std::move(alloc)) {}
/** Construct axis from an initializer list of unique values. /** Construct axis from an initializer list of unique values.
* *
* \param list `std::initializer_list` of unique values. * @param list `std::initializer_list` of unique values.
* \param meta description of the axis. * @param meta description of the axis.
* \param alloc allocator instance to use. * @param options see boost::histogram::axis::option (optional).
* @param alloc allocator instance to use.
*/ */
template <class U> template <class U>
category(std::initializer_list<U> list, metadata_type meta = {}, category(std::initializer_list<U> list, metadata_type meta = {},
allocator_type alloc = {}) options_type options = {}, allocator_type alloc = {})
: category(list.begin(), list.end(), std::move(meta), std::move(alloc)) {} : category(list.begin(), list.end(), std::move(meta), options, std::move(alloc)) {}
// kept for backward compatibility
template <class U>
category(std::initializer_list<U> list, metadata_type meta, allocator_type alloc)
: category(list.begin(), list.end(), std::move(meta), {}, std::move(alloc)) {}
/// Constructor used by algorithm::reduce to shrink and rebin (not for users). /// Constructor used by algorithm::reduce to shrink and rebin (not for users).
category(const category& src, index_type begin, index_type end, unsigned merge) category(const category& src, index_type begin, index_type end, unsigned merge)
// LCOV_EXCL_START: gcc-8 is missing the delegated ctor for no reason // LCOV_EXCL_START: gcc-8 is missing the delegated ctor for no reason
: category(src.vec_.begin() + begin, src.vec_.begin() + end, src.metadata(), : category(src.vec_.begin() + begin, src.vec_.begin() + end, src.metadata(), {},
src.get_allocator()) src.get_allocator())
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
{ {
@ -189,12 +211,17 @@ private:
template <class T> template <class T>
category(std::initializer_list<T>) category(std::initializer_list<T>)
->category<detail::replace_cstring<std::decay_t<T>>, null_type>; -> category<detail::replace_cstring<std::decay_t<T>>, null_type>;
template <class T, class M> template <class T, class M>
category(std::initializer_list<T>, M) category(std::initializer_list<T>, M)
->category<detail::replace_cstring<std::decay_t<T>>, -> category<detail::replace_cstring<std::decay_t<T>>,
detail::replace_cstring<std::decay_t<M>>>; detail::replace_cstring<std::decay_t<M>>>;
template <class T, class M, unsigned B>
category(std::initializer_list<T>, M, const option::bitset<B>&)
-> category<detail::replace_cstring<std::decay_t<T>>,
detail::replace_cstring<std::decay_t<M>>, option::bitset<B>>;
#endif #endif

View File

@ -34,9 +34,9 @@ namespace axis {
Binning is a O(1) operation. This axis bins faster than a regular axis. Binning is a O(1) operation. This axis bins faster than a regular axis.
@tparam Value input value type. Must be integer or floating point. @tparam Value input value type. Must be integer or floating point.
@tparam MetaData type to store meta data. @tparam MetaData type to store meta data.
@tparam Options see boost::histogram::axis::option (all values allowed). @tparam Options see boost::histogram::axis::option.
*/ */
template <class Value, class MetaData, class Options> template <class Value, class MetaData, class Options>
class integer : public iterator_mixin<integer<Value, MetaData, Options>>, class integer : public iterator_mixin<integer<Value, MetaData, Options>>,
@ -73,14 +73,17 @@ public:
/** Construct over semi-open integer interval [start, stop). /** Construct over semi-open integer interval [start, stop).
* *
* \param start first integer of covered range. * @param start first integer of covered range.
* \param stop one past last integer of covered range. * @param stop one past last integer of covered range.
* \param meta description of the axis. * @param meta description of the axis (optional).
* @param options see boost::histogram::axis::option (optional).
*/ */
integer(value_type start, value_type stop, metadata_type meta = {}) integer(value_type start, value_type stop, metadata_type meta = {},
options_type options = {})
: metadata_base(std::move(meta)) : metadata_base(std::move(meta))
, size_(static_cast<index_type>(stop - start)) , size_(static_cast<index_type>(stop - start))
, min_(start) { , min_(start) {
(void)options;
if (!(stop >= start)) if (!(stop >= start))
BOOST_THROW_EXCEPTION(std::invalid_argument("stop >= start required")); BOOST_THROW_EXCEPTION(std::invalid_argument("stop >= start required"));
} }
@ -217,6 +220,12 @@ integer(T, T, M)
-> integer<detail::convert_integer<T, index_type>, -> integer<detail::convert_integer<T, index_type>,
detail::replace_type<std::decay_t<M>, const char*, std::string>>; detail::replace_type<std::decay_t<M>, const char*, std::string>>;
template <class T, class M, unsigned B>
integer(T, T, M, const option::bitset<B>&)
-> integer<detail::convert_integer<T, index_type>,
detail::replace_type<std::decay_t<M>, const char*, std::string>,
option::bitset<B>>;
#endif #endif
} // namespace axis } // namespace axis

View File

@ -173,7 +173,7 @@ step_type<T> step(T t) {
@tparam Value input value type, must be floating point. @tparam Value input value type, must be floating point.
@tparam Transform builtin or user-defined transform type. @tparam Transform builtin or user-defined transform type.
@tparam MetaData type to store meta data. @tparam MetaData type to store meta data.
@tparam Options see boost::histogram::axis::option (all values allowed). @tparam Options see boost::histogram::axis::option.
*/ */
template <class Value, class Transform, class MetaData, class Options> template <class Value, class Transform, class MetaData, class Options>
class regular : public iterator_mixin<regular<Value, Transform, MetaData, Options>>, class regular : public iterator_mixin<regular<Value, Transform, MetaData, Options>>,
@ -213,14 +213,16 @@ public:
* @param start low edge of first bin. * @param start low edge of first bin.
* @param stop high edge of last bin. * @param stop high edge of last bin.
* @param meta description of the axis (optional). * @param meta description of the axis (optional).
* @param options see boost::histogram::axis::option (optional).
*/ */
regular(transform_type trans, unsigned n, value_type start, value_type stop, regular(transform_type trans, unsigned n, value_type start, value_type stop,
metadata_type meta = {}) metadata_type meta = {}, options_type options = {})
: transform_type(std::move(trans)) : transform_type(std::move(trans))
, metadata_base(std::move(meta)) , metadata_base(std::move(meta))
, size_(static_cast<index_type>(n)) , size_(static_cast<index_type>(n))
, min_(this->forward(detail::get_scale(start))) , min_(this->forward(detail::get_scale(start)))
, delta_(this->forward(detail::get_scale(stop)) - min_) { , delta_(this->forward(detail::get_scale(stop)) - min_) {
(void)options;
if (size() == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); if (size() == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required"));
if (!std::isfinite(min_) || !std::isfinite(delta_)) if (!std::isfinite(min_) || !std::isfinite(delta_))
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
@ -235,18 +237,21 @@ public:
* @param start low edge of first bin. * @param start low edge of first bin.
* @param stop high edge of last bin. * @param stop high edge of last bin.
* @param meta description of the axis (optional). * @param meta description of the axis (optional).
* @param options see boost::histogram::axis::option (optional).
*/ */
regular(unsigned n, value_type start, value_type stop, metadata_type meta = {}) regular(unsigned n, value_type start, value_type stop, metadata_type meta = {},
: regular({}, n, start, stop, std::move(meta)) {} options_type options = {})
: regular({}, n, start, stop, std::move(meta), options) {}
/** Construct bins with the given step size over real transformed range /** Construct bins with the given step size over real transformed range
* [start, stop). * [start, stop).
* *
* @param trans transform instance to use. * @param trans transform instance to use.
* @param step width of a single bin. * @param step width of a single bin.
* @param start low edge of first bin. * @param start low edge of first bin.
* @param stop upper limit of high edge of last bin (see below). * @param stop upper limit of high edge of last bin (see below).
* @param meta description of the axis (optional). * @param meta description of the axis (optional).
* @param options see boost::histogram::axis::option (optional).
* *
* The axis computes the number of bins as n = abs(stop - start) / step, * The axis computes the number of bins as n = abs(stop - start) / step,
* rounded down. This means that stop is an upper limit to the actual value * rounded down. This means that stop is an upper limit to the actual value
@ -254,27 +259,29 @@ public:
*/ */
template <class T> template <class T>
regular(transform_type trans, step_type<T> step, value_type start, value_type stop, regular(transform_type trans, step_type<T> step, value_type start, value_type stop,
metadata_type meta = {}) metadata_type meta = {}, options_type options = {})
: regular(trans, static_cast<index_type>(std::abs(stop - start) / step.value), : regular(trans, static_cast<index_type>(std::abs(stop - start) / step.value),
start, start,
start + static_cast<index_type>(std::abs(stop - start) / step.value) * start + static_cast<index_type>(std::abs(stop - start) / step.value) *
step.value, step.value,
std::move(meta)) {} std::move(meta), options) {}
/** Construct bins with the given step size over real range [start, stop). /** Construct bins with the given step size over real range [start, stop).
* *
* @param step width of a single bin. * @param step width of a single bin.
* @param start low edge of first bin. * @param start low edge of first bin.
* @param stop upper limit of high edge of last bin (see below). * @param stop upper limit of high edge of last bin (see below).
* @param meta description of the axis (optional). * @param meta description of the axis (optional).
* @param options see boost::histogram::axis::option (optional).
* *
* The axis computes the number of bins as n = abs(stop - start) / step, * The axis computes the number of bins as n = abs(stop - start) / step,
* rounded down. This means that stop is an upper limit to the actual value * rounded down. This means that stop is an upper limit to the actual value
* (start + n * step). * (start + n * step).
*/ */
template <class T> template <class T>
regular(step_type<T> step, value_type start, value_type stop, metadata_type meta = {}) regular(step_type<T> step, value_type start, value_type stop, metadata_type meta = {},
: regular({}, step, start, stop, std::move(meta)) {} options_type options = {})
: regular({}, step, start, stop, std::move(meta), options) {}
/// Constructor used by algorithm::reduce to shrink and rebin (not for users). /// Constructor used by algorithm::reduce to shrink and rebin (not for users).
regular(const regular& src, index_type begin, index_type end, unsigned merge) regular(const regular& src, index_type begin, index_type end, unsigned merge)
@ -397,20 +404,28 @@ private:
template <class T> template <class T>
regular(unsigned, T, T) regular(unsigned, T, T)
->regular<detail::convert_integer<T, double>, transform::id, null_type>; -> regular<detail::convert_integer<T, double>, transform::id, null_type>;
template <class T, class M> template <class T, class M>
regular(unsigned, T, T, M) regular(unsigned, T, T, M) -> regular<detail::convert_integer<T, double>, transform::id,
->regular<detail::convert_integer<T, double>, transform::id, detail::replace_cstring<std::decay_t<M>>>;
detail::replace_cstring<std::decay_t<M>>>;
template <class T, class M, unsigned B>
regular(unsigned, T, T, M, const option::bitset<B>&)
-> regular<detail::convert_integer<T, double>, transform::id,
detail::replace_cstring<std::decay_t<M>>, option::bitset<B>>;
template <class Tr, class T, class = detail::requires_transform<Tr, T>> template <class Tr, class T, class = detail::requires_transform<Tr, T>>
regular(Tr, unsigned, T, T)->regular<detail::convert_integer<T, double>, Tr, null_type>; regular(Tr, unsigned, T, T) -> regular<detail::convert_integer<T, double>, Tr, null_type>;
template <class Tr, class T, class M> template <class Tr, class T, class M>
regular(Tr, unsigned, T, T, M) regular(Tr, unsigned, T, T, M) -> regular<detail::convert_integer<T, double>, Tr,
->regular<detail::convert_integer<T, double>, Tr, detail::replace_cstring<std::decay_t<M>>>;
detail::replace_cstring<std::decay_t<M>>>;
template <class Tr, class T, class M, unsigned B>
regular(Tr, unsigned, T, T, M, const option::bitset<B>&)
-> regular<detail::convert_integer<T, double>, Tr,
detail::replace_cstring<std::decay_t<M>>, option::bitset<B>>;
#endif #endif

View File

@ -40,9 +40,9 @@ namespace axis {
Binning is a O(log(N)) operation. If speed matters and the problem domain Binning is a O(log(N)) operation. If speed matters and the problem domain
allows it, prefer a regular axis, possibly with a transform. allows it, prefer a regular axis, possibly with a transform.
@tparam Value input value type, must be floating point. @tparam Value input value type, must be floating point.
@tparam MetaData type to store meta data. @tparam MetaData type to store meta data.
@tparam Options see boost::histogram::axis::option (all values allowed). @tparam Options see boost::histogram::axis::option.
@tparam Allocator allocator to use for dynamic memory management. @tparam Allocator allocator to use for dynamic memory management.
*/ */
template <class Value, class MetaData, class Options, class Allocator> template <class Value, class MetaData, class Options, class Allocator>
@ -73,14 +73,18 @@ public:
/** Construct from iterator range of bin edges. /** Construct from iterator range of bin edges.
* *
* \param begin begin of edge sequence. * @param begin begin of edge sequence.
* \param end end of edge sequence. * @param end end of edge sequence.
* \param meta description of the axis. * @param meta description of the axis (optional).
* \param alloc allocator instance to use. * @param options see boost::histogram::axis::option (optional).
* @param alloc allocator instance to use (optional).
*/ */
template <class It, class = detail::requires_iterator<It>> template <class It, class = detail::requires_iterator<It>>
variable(It begin, It end, metadata_type meta = {}, allocator_type alloc = {}) variable(It begin, It end, metadata_type meta = {}, options_type options = {},
allocator_type alloc = {})
: metadata_base(std::move(meta)), vec_(std::move(alloc)) { : metadata_base(std::move(meta)), vec_(std::move(alloc)) {
(void)options;
if (std::distance(begin, end) < 2) if (std::distance(begin, end) < 2)
BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required"));
@ -96,27 +100,46 @@ public:
std::invalid_argument("input sequence must be strictly ascending")); std::invalid_argument("input sequence must be strictly ascending"));
} }
// kept for backward compatibility
template <class It, class = detail::requires_iterator<It>>
variable(It begin, It end, metadata_type meta, allocator_type alloc)
: variable(begin, end, std::move(meta), {}, std::move(alloc)) {}
/** Construct variable axis from iterable range of bin edges. /** Construct variable axis from iterable range of bin edges.
* *
* \param iterable iterable range of bin edges. * @param iterable iterable range of bin edges.
* \param meta description of the axis. * @param meta description of the axis (optional).
* \param alloc allocator instance to use. * @param options see boost::histogram::axis::option (optional).
* @param alloc allocator instance to use (optional).
*/ */
template <class U, class = detail::requires_iterable<U>> template <class U, class = detail::requires_iterable<U>>
variable(const U& iterable, metadata_type meta = {}, allocator_type alloc = {}) variable(const U& iterable, metadata_type meta = {}, options_type options = {},
: variable(std::begin(iterable), std::end(iterable), std::move(meta), allocator_type alloc = {})
: variable(std::begin(iterable), std::end(iterable), std::move(meta), options,
std::move(alloc)) {}
// kept for backward compatibility
template <class U, class = detail::requires_iterable<U>>
variable(const U& iterable, metadata_type meta, allocator_type alloc)
: variable(std::begin(iterable), std::end(iterable), std::move(meta), {},
std::move(alloc)) {} std::move(alloc)) {}
/** Construct variable axis from initializer list of bin edges. /** Construct variable axis from initializer list of bin edges.
* *
* @param list `std::initializer_list` of bin edges. * @param list `std::initializer_list` of bin edges.
* @param meta description of the axis. * @param meta description of the axis (optional).
* @param alloc allocator instance to use. * @param options see boost::histogram::axis::option (optional).
* @param alloc allocator instance to use (optional).
*/ */
template <class U> template <class U>
variable(std::initializer_list<U> list, metadata_type meta = {}, variable(std::initializer_list<U> list, metadata_type meta = {},
allocator_type alloc = {}) options_type options = {}, allocator_type alloc = {})
: variable(list.begin(), list.end(), std::move(meta), std::move(alloc)) {} : variable(list.begin(), list.end(), std::move(meta), options, std::move(alloc)) {}
// kept for backward compatibility
template <class U>
variable(std::initializer_list<U> list, metadata_type meta, allocator_type alloc)
: variable(list.begin(), list.end(), std::move(meta), {}, std::move(alloc)) {}
/// Constructor used by algorithm::reduce to shrink and rebin (not for users). /// Constructor used by algorithm::reduce to shrink and rebin (not for users).
variable(const variable& src, index_type begin, index_type end, unsigned merge) variable(const variable& src, index_type begin, index_type end, unsigned merge)
@ -221,26 +244,36 @@ private:
template <class T> template <class T>
variable(std::initializer_list<T>) variable(std::initializer_list<T>)
->variable<detail::convert_integer<T, double>, null_type>; -> variable<detail::convert_integer<T, double>, null_type>;
template <class T, class M> template <class T, class M>
variable(std::initializer_list<T>, M) variable(std::initializer_list<T>, M)
->variable<detail::convert_integer<T, double>, -> variable<detail::convert_integer<T, double>,
detail::replace_type<std::decay_t<M>, const char*, std::string>>; detail::replace_type<std::decay_t<M>, const char*, std::string>>;
template <class T, class M, unsigned B>
variable(std::initializer_list<T>, M, const option::bitset<B>&)
-> variable<detail::convert_integer<T, double>,
detail::replace_type<std::decay_t<M>, const char*, std::string>,
option::bitset<B>>;
template <class Iterable, class = detail::requires_iterable<Iterable>> template <class Iterable, class = detail::requires_iterable<Iterable>>
variable(Iterable) variable(Iterable) -> variable<
->variable< detail::convert_integer<
detail::convert_integer< std::decay_t<decltype(*std::begin(std::declval<Iterable&>()))>, double>,
std::decay_t<decltype(*std::begin(std::declval<Iterable&>()))>, double>, null_type>;
null_type>;
template <class Iterable, class M> template <class Iterable, class M>
variable(Iterable, M) variable(Iterable, M) -> variable<
->variable< detail::convert_integer<
detail::convert_integer< std::decay_t<decltype(*std::begin(std::declval<Iterable&>()))>, double>,
std::decay_t<decltype(*std::begin(std::declval<Iterable&>()))>, double>, detail::replace_type<std::decay_t<M>, const char*, std::string>>;
detail::replace_type<std::decay_t<M>, const char*, std::string>>;
template <class Iterable, class M, unsigned B>
variable(Iterable, M, const option::bitset<B>&) -> variable<
detail::convert_integer<
std::decay_t<decltype(*std::begin(std::declval<Iterable&>()))>, double>,
detail::replace_type<std::decay_t<M>, const char*, std::string>, option::bitset<B>>;
#endif #endif

View File

@ -21,6 +21,7 @@
using namespace boost::histogram; using namespace boost::histogram;
namespace tr = axis::transform; namespace tr = axis::transform;
namespace op = axis::option;
// tests requires a C++17 compatible compiler // tests requires a C++17 compatible compiler
@ -43,6 +44,10 @@ int main() {
regular<float, tr::sqrt, std::string>); regular<float, tr::sqrt, std::string>);
BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, 0)), BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, 0)),
regular<double, tr::sqrt, int>); regular<double, tr::sqrt, int>);
BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0, 1, "x", op::growth)),
regular<double, tr::id, std::string, op::growth_t>);
BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, "x", op::growth)),
regular<double, tr::sqrt, std::string, op::growth_t>);
} }
{ {
@ -53,6 +58,8 @@ int main() {
BOOST_TEST_TRAIT_SAME(decltype(integer(1.0f, 2.0f)), integer<float, null_type>); BOOST_TEST_TRAIT_SAME(decltype(integer(1.0f, 2.0f)), integer<float, null_type>);
BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, "foo")), integer<int, std::string>); BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, "foo")), integer<int, std::string>);
BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, 0)), integer<int, int>); BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, 0)), integer<int, int>);
BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, "foo", op::growth)),
integer<int, std::string, op::growth_t>);
} }
{ {
@ -63,6 +70,8 @@ int main() {
BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 0, 1}, "foo")), BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 0, 1}, "foo")),
variable<double, std::string>); variable<double, std::string>);
BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, 0)), variable<double, int>); BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, 0)), variable<double, int>);
BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, "foo", op::underflow)),
variable<double, std::string, op::underflow_t>);
BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}})), BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}})),
variable<double, null_type>); variable<double, null_type>);
@ -72,6 +81,8 @@ int main() {
variable<double, std::string>); variable<double, std::string>);
BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}}, 0)), BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}}, 0)),
variable<double, int>); variable<double, int>);
BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, "foo", op::growth)),
variable<double, std::string, op::growth_t>);
} }
{ {
@ -80,6 +91,8 @@ int main() {
BOOST_TEST_TRAIT_SAME(decltype(category{"x", "y"}), category<std::string, null_type>); BOOST_TEST_TRAIT_SAME(decltype(category{"x", "y"}), category<std::string, null_type>);
BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, "foo")), category<int, std::string>); BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, "foo")), category<int, std::string>);
BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, 0)), category<int, int>); BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, 0)), category<int, int>);
BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, "foo", op::growth)),
category<int, std::string, op::growth_t>);
} }
{ {