Why isn't std::next/prev templated by distance like std::advance? - c++

Out of curiosity, what's the rationale to use a template parameter for std::advance()'s distance type, but use the iterator's difference_type for the distance in std::next() and std::prev()?
Why not use the same approach (either one)?
Follow up:
Presence of default n = 1 does not seem to prevent next to be templated by Distance as was suggested in the answer below. This compiles:
#include <iterator>
#include <set>
template<typename InputIt,
typename Distance = typename std::iterator_traits<InputIt>::difference_type>
InputIt my_next(InputIt it, Distance n = 1)
{
std::advance(it, n);
return it;
}
int main()
{
std::set<int> s;
my_next(s.begin());
my_next(s.begin(), 10ul);
return 0;
}

It is needed to be able to compile both std::next(it, n) and std::next(it) with default 1:
template<typename InputIt , typename Distance>
InputIt
next(InputIt it, Distance n = 1)
{
std::advance(it, n);
return it;
}
void foo(int *p)
{
next(p, 1); // ok
next<int*, int>(p); // ok
next(p); // error: no matching function for call to 'next(int*&)'
}
There is a discussion of possible approaches to this overload resolution issue in gcc bugzilla: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40497

Related

partial_sum() position of previous

Using partial_sum(), I am trying to get the position from previous during the recurrence. I don't understand the result. I was expecting to get :
recurrence i=0
recurrence i=1
...
As the recurrence unfolds. But I am getting :
recurrence i=-48115006
recurrence i=-48115006
...
What am doing wrong ?
#include <vector>
#include <algorithm>
#include <numeric>
#include <stdio.h>
using namespace std;
int main()
{
const int n=15;
vector<vector<int> > vv(n+1);
vv[0]={42};
auto next=[&](const vector<int>& previous, const vector<int>&){
const int i = &previous - &vv[0];
printf("recurrence i=%d\n", i);
fflush(stdout);
vector<int> v;
return v;
};
partial_sum(vv.begin(), vv.end(), vv.begin(), next);
}
The implementation for partial_sum that you are using is probably similar to the one described in cppreference, Possible implementation, Second version:
template<class InputIt, class OutputIt, class BinaryOperation>
constexpr // since C++20
OutputIt partial_sum(InputIt first, InputIt last,
OutputIt d_first, BinaryOperation op)
{
if (first == last)
return d_first;
typename std::iterator_traits<InputIt>::value_type sum = *first;
*d_first = sum;
while (++first != last)
{
sum = op(std::move(sum), *first); // std::move since C++20
*++d_first = sum;
}
return ++d_first;
}
That being the case, the first argument that partial_sum passes to op (the binary operation, next in your code) is fix: it's a reference to an accumulator. It is the second argument the one that varies: it's a reference to the current element in each iteration (starting at the second element). But, in your example, you don't use this second argument to set i. Instead, you always use &vv[0], which is also a fix value (unless vv changes in size, which is not the case). So it's expected that you are always printing the same value: the difference of two fix addresses.
You can see it working here with some more debugging output.

C++ functors behavior

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
struct cmp {
bool operator()(const int& i, const int& j) const{
return false;
}
} ;
struct cmp2 {
bool operator()(const int& i, const int& j) const{
return false;
}
} cmp2_item;
class Solution {
public:
vector<int> smth(vector<int> arr, int k) {
// nth_element(arr.begin(), arr.begin()+k, arr.end(), cmp); #ERROR
// nth_element(arr.begin(), arr.begin()+k, arr.end(), cmp()); #WORKS
// nth_element(arr.begin(), arr.begin()+k, arr.end(), cmp2_item); # WORKS
// sort(arr.begin(), arr.end(), cmp); #ERROR
// sort(arr.begin(), arr.end(), cmp()); #WORKS
// set<int, cmp> s; # WORKS
// set<int, cmp2_item> s; # ERROR
return {};
}
};
int main() {
// your code goes here
Solution s;
s.smth({}, 1);
return 0;
}
I want to understand why this code behaves in this way.
for nth_element we expect a functor so it makes sense to include like cmp(), but why does it start working without the (), when i instantiate the struct and use that?
Similar in sort
while when using it for a comparator for a set, it only works if the struct is not instantiated and without the ()
Can someone please clarify using the signatures why this is so?
nth_element: template< class RandomIt, class Compare > void nth_element ( RandomIt first, RandomIt nth, RandomIt last, Compare comp );
sort
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
set:
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;
One part of this is that cmp2_item is not a type, its an instance of the type cmp2. So you can't pass that as a class type. You might be able to do:
set<int, cmp> s; //# WORKS
set<int, decltype(cmp2_item)> s2; //# NOW WORKS
For these:
// Not ok because cmp is not a function comparison object, its a type
nth_element(arr.begin(), arr.begin()+k, arr.end(), cmp); #ERROR
// Ok because this is effectively passing a functor (and not just a type)
// I believe this takes a copy of the functor type (by construction), I
// am not quite so clear on the inner workings of the compiler in this
// case. I guess its by type comparison, but possible compiler
// implementation specific?
nth_element(arr.begin(), arr.begin()+k, arr.end(), cmp()); #WORKS
// This is ok because it passes an actual comparison object (that has
// operator () defined).
nth_element(arr.begin(), arr.begin()+k, arr.end(), cmp2_item); # WORKS
Basically you have to look more closely at what you are passing: a type, an object or a function - and what the specific STL accepts as a parameter.
Note:
comparison function object (i.e. an object that satisfies the requirements of Compare) which returns ​true if the first argument is less than (i.e. is ordered before) the second.
See here: enter link description here

What STL algorithm can determine if exactly one item in a container satisfies a predicate?

I need an STL algorithm that takes a predicate and a collection and returns true if one and only one member of the collection satisfies the predicate, otherwise returns false.
How would I do this using STL algorithms?
E.g., to replace the following with STL algorithm code to express the same return value.
int count = 0;
for( auto itr = c.begin(); itr != c.end(); ++itr ) {
if ( predicate( *itr ) ) {
if ( ++count > 1 ) {
break;
}
}
}
return 1 == count;
Two things come to my mind:
std::count_if and then compare the result to 1.
To avoid traversing the whole container in case eg the first two elements already match the predicate I would use two calls looking for matching elements. Something along the line of
auto it = std::find_if(begin,end,predicate);
if (it == end) return false;
++it;
return std::none_of(it,end,predicate);
Or if you prefer it more compact:
auto it = std::find_if(begin,end,predicate);
return (it != end) && std::none_of(std::next(it),end,predicate);
Credits goes to Remy Lebeau for compacting, Deduplicator for debracketing and Blastfurnance for realizing that we can also use none_of the std algorithms.
You can use std::count_if† to count and return if it is one.
For example:
#include <iostream>
#include <algorithm> // std::count_if
#include <vector> // std::vector
#include <ios> // std::boolalpha
template<class Iterator, class UnaryPredicate>
constexpr bool is_count_one(Iterator begin, const Iterator end, UnaryPredicate pred)
{
return std::count_if(begin, end, pred) == 1;
}
int main()
{
std::vector<int> vec{ 2, 4, 3 };
// true: if only one Odd element present in the container
std::cout << std::boolalpha
<< is_count_one(vec.cbegin(), vec.cend(),
[](const int ele) constexpr noexcept -> bool { return ele & 1; });
return 0;
}
†Update: However, std::count_if counts entire element in the container, which is not good as the algorithm given in the question. The best approach using the standard algorithm collections has been mentioned in #formerlyknownas_463035818 's answer.
That being said, OP's approach is also good as the above mentioned best standard approach, where a short-circuiting happens when count reaches 2. If someone is interested in a non-standard algorithm template function for OP's approach, here is it.
#include <iostream>
#include <vector> // std::vector
#include <ios> // std::boolalpha
#include <iterator> // std::iterator_traits
template<class Iterator, class UnaryPredicate>
bool is_count_one(Iterator begin, const Iterator end, UnaryPredicate pred)
{
typename std::iterator_traits<Iterator>::difference_type count{ 0 };
for (; begin != end; ++begin) {
if (pred(*begin) && ++count > 1) return false;
}
return count == 1;
}
int main()
{
std::vector<int> vec{ 2, 3, 4, 2 };
// true: if only one Odd element present in the container
std::cout << std::boolalpha
<< is_count_one(vec.cbegin(), vec.cend(),
[](const int ele) constexpr noexcept -> bool { return ele & 1; });
return 0;
}
Now that can be generalized, by providing one more parameter, the number of N element(s) has/ have to be found in the container.
template<typename Iterator>
using diff_type = typename std::iterator_traits<Iterator>::difference_type;
template<class Iterator, class UnaryPredicate>
bool has_exactly_n(Iterator begin, const Iterator end, UnaryPredicate pred, diff_type<Iterator> N = 1)
{
diff_type<Iterator> count{ 0 };
for (; begin != end; ++begin) {
if (pred(*begin) && ++count > N) return false;
}
return count == N;
}
Starting from formerlyknownas_463035818's answer, this can be generalized to seeing if a container has exactly n items that satisfy a predicate. Why? Because this is C++ and we're not satisfied until we can read email at compile time.
template<typename Iterator, typename Predicate>
bool has_exactly_n(Iterator begin, Iterator end, size_t count, Predicate predicate)
{
if(count == 0)
{
return std::none_of(begin, end, predicate);
}
else
{
auto iter = std::find_if(begin, end, predicate);
return (iter != end) && has_exactly_n(std::next(iter), end, count - 1, predicate);
}
}
Using std::not_fn to negate a predicate
As the core of the algorithm of this question (as has been elegantly covered by combining std::find_if and std::none_of in the accepted answer), with short-circuiting upon failure, is to scan a container for a unary predicate and, when met, continue scanning the rest of the container for the negation of the predicate, I will mention also the negator std::not_fn introduced in C++17, replacing the less useful std::not1 and std::not2 constructs.
We may use std::not_fn to implement the same predicate logic as the accepted answer (std::find_if conditionally followed by std::none_of), but with somewhat different semantics, replacing the latter step (std::none_of) with std::all_of over the negation of the unary predicate used in the first step (std::find_if). E.g.:
// C++17
#include <algorithm> // std::find_if
#include <functional> // std::not_fn
#include <ios> // std::boolalpha
#include <iostream>
#include <iterator> // std::next
#include <vector>
template <class InputIt, class UnaryPredicate>
constexpr bool one_of(InputIt first, InputIt last, UnaryPredicate p) {
auto it = std::find_if(first, last, p);
return (it != last) && std::all_of(std::next(it), last, std::not_fn(p));
}
int main() {
const std::vector<int> v{1, 3, 5, 6, 7};
std::cout << std::boolalpha << "Exactly one even number : "
<< one_of(v.begin(), v.end(), [](const int n) {
return n % 2 == 0;
}); // Exactly one even number : true
}
A parameter pack approach for static size containers
As I’ve already limited this answer to C++14 (and beyond), I’ll include an alternative approach for static size containers (here applied for std::array, specifically), making use of std::index_sequence combined with parameter pack expansion:
#include <array>
#include <ios> // std::boolalpha
#include <iostream>
#include <utility> // std::(make_)index_sequence
namespace detail {
template <typename Array, typename UnaryPredicate, std::size_t... I>
bool one_of_impl(const Array& arr, const UnaryPredicate& p,
std::index_sequence<I...>) {
bool found = false;
auto keep_searching = [&](const int n){
const bool p_res = found != p(n);
found = found || p_res;
return !found || p_res;
};
return (keep_searching(arr[I]) && ...) && found;
}
} // namespace detail
template <typename T, typename UnaryPredicate, std::size_t N,
typename Indices = std::make_index_sequence<N>>
auto one_of(const std::array<T, N>& arr,
const UnaryPredicate& p) {
return detail::one_of_impl(arr, p, Indices{});
}
int main() {
const std::array<int, 5> a{1, 3, 5, 6, 7};
std::cout << std::boolalpha << "Exactly one even number : "
<< one_of(a, [](const int n) {
return n % 2 == 0;
}); // Exactly one even number : true
}
This will also short-circuit upon early failure (“found more than one”), but will contain a few more simple boolean comparisons than in the approach above.
However, note that this approach could have its draw-backs, particularly for optimized code for container inputs with many elements, as is pointed out by #PeterCordes in a comment below. Citing the comment (as comments are not guaranteed to persist over time):
Just because the size is static doesn't mean that fully unrolling the loop with templates is a good idea. In the resulting asm, this needs a branch every iteration anyway to stop on found, so that might as well be a loop-branch. CPUs are good at running loops (code caches, loopback buffers). Compilers will fully unroll static-sized loops based on heuristics, but probably won't roll this back up if a is huge. So your first one_of implementation has the best of both worlds already, assuming a normal modern compiler like gcc or clang, or maybe MSVC

Extract input iterator from std::copy and std::copy_n

I trying to implement an unserialization method that take an input iterator and perform a series of chunk reads (using std::copy and std::copy_n). Something like this (just an example):
template <class InputIt>
InputIt unserialize(InputIt it)
{
std::copy_n(it, sizeof(header_type), reinterpret_cast<char*>(&header));
std::copy_n(it, header.payload_size, std::back_inserter(payload));
it = optional.unserialize(it);
return it;
}
How do I advance input iterator in this case so each following call to std::copy_n continue read from it and I can finally return it?
I want to be generic to iterator categories (especially RandomAccessIterator and InputIterator) for performance reasons and hope it is possible to use std::copy methods without need to rewrite these. Stuff like bound checking and such will be done by iterator adapter or checked before unserialization call if size is known.
What do not work nor acceptable:
Using std::copy_n<InputIt&>(it, ...) may work for some categories but not for all and it's too unreliable.
Using std::advance after each call leads to rereading same block again for some iterators. Not preferable and may be impossible for some sources.
UPDATE Making iterator reference adapter doesn't help as random access iterator version of copy_n return pointer to past the last element copied while input iterator version return pointer to the last element copied. So I guess own version of copy_n works best with additional iterator adapter for bound checking.
For random access iterator this form can be used - and it is fine:
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input(InputIt it, N dist, OutputIt outIt)
{
std::copy_n(it, dist, outIt);
return std::next(it, dist);
}
Unfortunately - problems are when we want to deal with one pass input iterator - like here (got 'd' - not 'c'):
std::string s = "abcd";
std::istringstream ss{s};
auto e = copy_n_advance_input(std::istream_iterator<char>(ss),
2,
std::ostream_iterator<char>(std::cout, ","));
std::cout << "\n" << *e << "\n";
So it seems it is needed, as usual in STL, two forms:
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input_impl(InputIt it, N dist, OutputIt outIt,
std::input_iterator_tag)
{
while (dist-- > 0)
{
*outIt = *it;
++outIt;
++it;
}
return it;
}
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input_impl(InputIt it, N dist, OutputIt outIt,
std::random_access_iterator_tag)
{
std::copy_n(it, dist, outIt);
return std::next(it, dist);
}
template <class InputIt, class N, class OutputIt>
InputIt copy_n_advance_input(InputIt it, N dist, OutputIt outIt)
{
return copy_n_advance_input_impl(it, dist, outIt, typename std::iterator_traits<InputIt>::iterator_category {});
}
Note, the proposed version for std::input_iterator_tag is not as efficient as in STL (at least for gcc) - it does extra iteration for input - this iteration is not necessary to perform copy - but it is needed to return beginning of "after copy" range (stl_algo.h):
754 template<typename _InputIterator, typename _Size, typename _OutputIterator>
755 _OutputIterator
756 __copy_n(_InputIterator __first, _Size __n,
757 _OutputIterator __result, input_iterator_tag)
758 {
759 if (__n > 0)
760 {
761 while (true)
762 {
763 *__result = *__first;
764 ++__result;
765 if (--__n > 0)
766 ++__first;
767 else
768 break;
769 }
770 }
771 return __result;
772 }
Last note - it is wiser to use, for random-access-iterators (like std::vector::iterator) the version that just calls std algorithms - because they can be even more optimized - e.g. for contiguous memory iterator over POD types - that can be just memcpy'ied. Or some specialization for std::vector<bool> or std::deque<T> exist, that uses their internal structure to perform copy in most efficient way.
You could create an iterator adapter that always works through a reference to the supplied iterator. Here's the basic skeleton of such an adapter:
#include <iterator>
template<typename InputIterator>
struct IteratorReference
{
InputIterator& it;
IteratorReference(InputIterator& it)
: it(it)
{}
// {copy, move, destructor} == default
// iterator methods (TODO: add the rest)
IteratorReference& operator++()
{ ++it; return this; }
typename InputIterator::reference operator*()
{ return *it; }
// Convert back to original iterator
operator InputIterator() const
{ return it; }
};
template<typename InputIterator>
IteratorReference<InputIterator> make_iterator_reference(InputIterator it)
{
return it;
}
To use it, simply create and use a wrapper in place of the original iterator:
#include <algorithm>
#include <vector>
struct Header
{
std::size_t payload_size;
};
template <class InputIt>
InputIt unserialize(InputIt it, Header& header, std::vector<char>& payload)
{
auto i_ref = make_iterator_reference(it);
std::copy_n(i_ref, sizeof header, reinterpret_cast<char*>(&header));
std::copy_n(i_ref, header.payload_size, std::back_inserter(payload));
i_ref = optional.unserialize(i_ref);
return i_ref;
}
I know this is an old question, but...
Recently I've run into similar issue, and I feel pretty sad when I see there isn't any good solution for this problem...
Nevertheless, I've tried to write an iterator wrapper like what Toby Speight said, and I've extended it a bit.
This wrapper is only used for InputIterator, because other kind of iterators supported by std::copy and std::copy_n are multipass iterators, and it's possible to directly use std::next and std::advance on them instead of using this wrapper.
template<typename Iterator>
struct Wrapper {
using traits = std::iterator_traits<Iterator>;
using difference_type = typename Traits::difference_type;
using reference = typename Traits::reference;
//...
reference operator*() const { return *(*(this->current)); }
//need implement operator++(int) too, in the similar way
Wrapper& operator++() {
if(this->indicator != 0) {
++(*(this->current));
--this->indicator;
}
return *this;
}
//need to implement operator!= too, in the similar way
bool operator==(const Wrapper& other) const {
return *(this->current) == *(other.current) or this->indicator == other.indicator;
}
Iterator* current;
difference_type indicator;
};
template<typename Iterator>
struct Range {
using category = typename std::iterator_traits<Iterator>::iterator_category;
//...
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
constexpr bool isForwardOrAbove() {
return std::is_base_of_v<std::forward_iterator_tag, category>;
}
using iterator = std::conditional_t<isForwardOrAbove(), Iterator, Wrapper<Iterator>>;
std::pair<iterator, iterator> splitSubRange(difference_type n) {
if constexpr (isForwardOrAbove()) {
//forward iterators are multi-pass iterators, so using std::advance on one iterator will not invalidate its copies
auto oldBegin = this->begin;
std::advance(this->begin, n);
return {oldBegin, std::next(oldBegin, n)};
}
else {
//non-forward-iterator
return {{&(this->begin), n}, {&(this->end), 0}};
}
}
Iterator begin;
Iterator end;
}
To use them, firstly you need a Range object which holds iterators, and use the splitSubRange method to obtain plain iterators, or, if they are only InputIterators, iterator wrappers.
template<typename InputIterator>
InputIterator unserialize(InputIterator begin, InputIterator end) {
auto range = Range<InputIterator>{begin, end};
auto [begin, end] = range.splitSubRange(sizeof(header_type));
//before having "used" the iterator obtained from range, you shouldn't use range again.
std::copy(begin, end, header.begin());
//after having "used" the iterator, you can use the range object to obtain the next sub-range
auto [begin2, dummy] = range.splitSubRange(sizeof(header_type_2));
std::copy_n(begin2, sizeof(header_type_2), header2.begin());
...
return range.begin;
}

Splitting std::vector based on some criteria

I have a vector which contain some data. I want to split it into const number of vectors depending on some criteria. For example:
using Point=std::pair<int,int>;
std::array<std::vector<Point>,4> split_to_4(const std::vector<Point>& data,std::function<size_t(Point)> criteria);
int main(){
std::vector<Point> data;
//fill data
auto results=split_to_4(data,[](const Point& p){
if(cond1) return 0;
if(cond2) return 1;
if(cond3) return 2;
return 3;
});
}
What is the best way to implement split_to_4? My current attempt is:
std::array<std::vector<Point>,4> split_to_4(const std::vector<Point>& data,std::function<size_t(Point)> criteria){
std::array<std::vector<Point>,4> result;
for (const auto& p : data){
areas_regions[criteria(p)].emplace_back(p);
}
return result;
}
Any better.. More std way to do it?
By Better, I mean: more readable... depend on iterator... depend on some std functions...
You can do this in place with multiple calls to std::partition:
// Returns iterators to the three partition points in the range
template<class ForwardIt, class Which>
auto split4(ForwardIt first, ForwardIt last, Which which) {
std::array<ForwardIt, 3> ret;
ret[0] = std::partition(first, last,
[&](const auto &v){return which(v) == 0;});
ret[1] = std::partition(ret[0], last,
[&](const auto &v){return which(v) == 1;});
ret[2] = std::partition(ret[1], last,
[&](const auto &v){return which(v) == 2;});
return ret;
}
Of course you can also pass and use the conditions directly instead of proxiing through some which function if you so desire.
One could also trivially rewrite this with a loop to generalize it to splitN if necessary. (Watch out though, the complexity of this approach is O(N * n) for a range with n elements. This will probably be unreasonably slow for big N. On the other hand, we get swaps instead of copies, which may help if copying is expensive (compared to calling which). If performance is critical, measure.)
If you need the relative order of elements in each group preserved, std::stable_partition is your friend.
Just noticed the C++11 tag: The above code is C++14. For C++11 compatibility, simply change the autos I used to the explicit types, i.e. use std::array<ForwardIt, 3> as the return type and const std::iterator_traits<ForwardIt>::value_type& for the lambdas.
I'll leave that as is for brevity, this last paragraph completes the answer for the pre-C++14 folks.
update:
probably the most STL-like way:
Features:
Iterator-based so choice of source and destination containers is left to the caller
Source iterators may be move-iterators if move-partitioning is required, or leave as normal iterators to make a copy
Linear time complexity
Stable ordering of results (ref std::stable_partition)
-
#include <array>
#include <vector>
#include <utility>
#include <cassert>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class Iter, class OutIter, class Which>
auto split_n(Iter first, Iter last,
OutIter outfirst, std::size_t N,
Which&& which)
{
while (first != last) {
auto index = which(*first);
assert (index < N);
std::next(outfirst, index) -> push_back(*first);
++ first;
}
}
template<class Iter, class OutIter, class Which>
auto split_to(Iter first, Iter last,
OutIter outfirst, OutIter outlast,
Which&& which)
{
return split_n(first, last, outfirst,
std::distance(outfirst, outlast),
std::forward<Which>(which));
}
int main(){
std::vector<Point> source;
std::array<std::vector<Point>, 4> dest { };
split_n(source.begin(), source.end(),
dest.begin(), dest.size(),
which_bucket);
// or
split_to(source.begin(), source.end(),
dest.begin(), dest.end(),
which_bucket);
// or with move request:
split_to(std::make_move_iterator(source.begin()),
std::make_move_iterator(source.end()),
dest.begin(), dest.end(),
which_bucket);
}
another way
#include <array>
#include <vector>
#include <utility>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class Iter, class Which>
auto split4(Iter first, Iter last, Which&& which)
{
std::array<std::vector<Point>, 4> result {};
while (first != last) {
result[which(*first)].push_back(*first);
++first;
}
return result;
}
int main(){
std::vector<Point> data;
auto results = split4(data.begin(), data.end(), which_bucket);
}
Here's another way which honours any custom allocator in the vector:
#include <array>
#include <vector>
#include <utility>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class T, class A, class Which>
auto split4(const std::vector<T,A>& v,
Which&& which)
{
using vec_type = std::vector<T,A>;
std::array<std::vector<T,A>, 4> result {
vec_type(v.get_allocator()),
vec_type(v.get_allocator()),
vec_type(v.get_allocator()),
vec_type(v.get_allocator())
};
for (auto& p : v) {
result[which(p)].push_back(p);
}
return result;
}
int main(){
std::vector<Point> data;
auto results = split4(data, which_bucket);
}