Apologises for the ambiguous title.
Here is my code:
struct LowHigh
{
};
struct HighLow
{
};
template < class LookupScheme>
struct ladder_base
{
using value_type = price_depth;
using ladder_type = std::vector< value_type >;
template < class T >
struct lookup;
template <>
struct lookup< LowHigh >
{
static constexpr auto func = std::upper_bound< ladder_type::iterator, value_type >;
};
template <>
struct lookup< HighLow >
{
static constexpr auto func = std::lower_bound< ladder_type::iterator, value_type >;
};
void
insert(value_type v)
{
auto iter = lookup< LookupScheme >::func(std::begin(data_), std::end(data_), v);
data_.insert(iter, std::move(v));
}
protected:
std::vector< value_type > data_;
};
} // namespace detail
struct bid_ladder : detail::ladder_base< detail::HighLow >
{
};
struct offer_ladder : detail::ladder_base< detail::LowHigh >
{
};
I’m specialising lookup::func depending on the scheme passed as a template type. There are currently only two possible schemes: LowHigh & HighLow. This has the effect of determining how the underlying vector is sorted.
Is there a more idiomatic/cleaner way to express this logic?
>Solution :
These algorithms take a comparison object as their last parameter – so you can use that to your advantage.
template < class Compare >
struct ladder_base
{
using value_type = price_depth;
using ladder_type = std::vector< value_type >;
void
insert(value_type v)
{
auto iter = std::upper_bound(data_.begin(), data_.end(), v, Compare{} );
data_.insert(iter, std::move(v));
}
protected:
std::vector< value_type > data_;
};
And then use ladder_base<std::less<>> or ladder_base<std::greater<>>, depending on which sort order you want.
Note that std::lower_bound and std::upper_bound are not antonyms, so your original wasn’t really correct. lower_bound gives you the first element >= x and upper_bound gives you the first element > x. So changing from one to the other doesn’t change your sort order (both require increasing order), only the comparison object affects that.
For instance:
std::vector<int> v = {1, 3, 5, 7};
auto i = std::lower_bound(v.begin(), v.end(), 3); // this is the 3
auto j = std::upper_bound(v.begin(), v.end(), 3); // this is the 5
Note that the vector is sorted in increasing order, but both calls are perfectly well-formed. If you wanted a reverse sort, you’d have to pass std::greater{} in as the comparison object (as I’m showing).
But either way, you want to use std::upper_bound – regardless of sort order.