How to encapsulate custom iterator in function using boost-range - c++

Lately I was using boost-range to create ranges over elements satisfying certain criteria. In all cases I'm using the same kind of filtered range all the time, so that I tried to encapsulate this behaviour in an external function.
This was the point where my problems started. Consider the following example.
#include <boost/range/adaptor/filtered.hpp>
#include <iostream>
#include <vector>
auto myFilter = [](const std::vector<int>& v, int r) {
return v | boost::adaptors::filtered([&r](auto v) { return v%r == 0; });
};
int main(int argc, const char* argv[])
{
using namespace boost::adaptors;
std::vector<int> input{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto& element : input | filtered([](auto v) {return v % 2 == 0; } ))
{
std::cout << "Element = " << element << std::endl;
}
std::cout << std::endl;
for (auto& element : myFilter(input,4))
{
std::cout << "Element = " << element << std::endl;
}
return 0;
}
The first for-loop behaves as expected printing 4 and 8. The second for-loop however prints just 4. Why is that?
My second idea was to implement a class having a begin() and end() function. This should be a thin wrapper around a range object.
This was the solution, after fiddling out the type of the range iterator.
struct MyFilter {
MyFilter(const std::vector<int>& c, int r) : c(c), r(r), f([&r](auto v) { return v%r == 0; }) {
}
boost::range_detail::filtered_range<std::function<bool(int)>, std::vector<int>>::iterator begin() {
return rng.begin();
}
boost::range_detail::filtered_range<std::function<bool(int)>, std::vector<int>>::iterator end() {
return rng.end();
}
std::vector<int> c;
int r;
std::function<bool(int)> f;
boost::range_detail::filtered_range < std::function<bool(int)>, std::vector<int>> rng=c | boost::adaptors::filtered(f);
};
Usage should be something like:
for (auto& element : MyFilter(input, 4)) {
std::cout << "Element = " << element << std::endl;
}
Unfortunately, it prints again just the 4. Whichs is quite strange to me??
Now, I got the solution by myself. I have to remove the "&" in my lambda function to make it work!

In:
auto myFilter = [](const std::vector<int>& v, int r) {
return v | boost::adaptors::filtered([&r](auto v) { return v%r == 0; });
};
It returns another range adaptor while r captured by reference becomes a dangling reference. To fix it capture r by value:
auto myFilter = [](const std::vector<int>& v, int r) {
return v | boost::adaptors::filtered([r](auto v) { return v%r == 0; });
}; ^
+--- capture by value

Related

Is there a cost difference between returning a function by reference vs passing the object through a void function?

When would you choose to prefer one way over the other? When I ran the bottom example through Godbolt. The return by reference function calls a move at the very end. If the container being passed in was large enough would that be costly? Or would it simply move the pointers around?
Ex:
#include <iostream>
#include <vector>
template<typename T>
void print(const T& v)
{
for(const auto& e : v)
std::cout << e << " ";
std::cout << std::endl;
}
void byVoid(std::vector<int>& v)
{
for(auto && e : v)
e = 0;
}
std::vector<int>& byRef(std::vector<int>& v)
{
for(auto && e : v)
e = 0;
return v;
}
int main()
{
std::vector<int> test1 = {0,1,2,3,4,5,6,7,8,9};
std::vector<int> test2 = {0,1,2,3,4,5,6,7,8,9};
print(test1);
print(test2);
byVoid(test1);
test2 = byRef(test2);
print(test1);
print(test2);
}

C++ - Iterate over vector of doubles as tuples

I have a C++ vector of doubles, which is guaranteed to have an even number of elements. This vector stores the coordinates of a set of points as x, y coordinates:
A[2 * i ] is the x coordinate of the i'th point.
A[2 * i + 1] is the y coordinate of the i'th point.
How to implement an iterator that allows me to use STL style algorithms (one that takes an iterator range, where dereferencing an iterator gives back the pair of doubles corresponding to the x, y coordinates of the corresponding point) ?
I'm using C++17 if that helps.
We can use range-v3, with two adapters:
chunk(n) takes a range and adapts it into a range of non-overlapping ranges of size n
transform(f) takes a range of x and adapts it into a range of f(x)
Putting those together we can create an adaptor which takes a range and yields a range of non-overlapping pairs:
auto into_pairs = rv::chunk(2)
| rv::transform([](auto&& r){ return std::pair(r[0], r[1]); });
Using the r[0] syntax assumes that the input range is random-access, which in this case is fine since we know we want to use it on a vector, but it can also be generalized to work for forward-only ranges at the cost of a bit more syntax:
| rv::transform([](auto&& r){
auto it = ranges::begin(r);
auto next = ranges::next(it);
return std::pair(*it, *next);
})
Demo, using fmt for convenient printing:
int main() {
std::vector<int> v = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
auto into_pairs = rv::chunk(2)
| rv::transform([](auto&& r){ return std::pair(r[0], r[1]); });
// prints {(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)}
fmt::print("{}\n", v | into_pairs);
}
It's unclear from the question if you wanted pair<T, T>s or pair<T&, T&>s. The latter is doable by providing explicit types to std::pair rather than relying on class template argument deduction.
C++ is a bit of a moving target - also when it comes to iterators (c++20 has concepts for that...). But would it not be nice to have a lazy solution to the problem. I.e. The tuples get generated on the fly, without casting (see other answers) and without having to write a loop to transform a vector<double> to a vector<tuple<double,double>>?
Now I feel I need a disclaimer because I am not sure this is entirely correct (language lawyers will hopefully point out, if I missed something). But it compiles and produces the expected output. That is something, yes?! Yes.
The idea is to build a pseudo container (which actually is just a facade to an underlying container) with an iterator of its own, producing the desired output type on the fly.
#include <vector>
#include <tuple>
#include <iostream>
#include <iterator>
template <class SourceIter>
struct PairWise {
PairWise() = delete;
PairWise(SourceIter first, SourceIter last)
: first{first}
, last{last}
{
}
using value_type =
typename std::tuple<
typename SourceIter::value_type,
typename SourceIter::value_type
>;
using source_iter = SourceIter;
struct IterState {
PairWise::source_iter first;
PairWise::source_iter last;
PairWise::source_iter current;
IterState(PairWise::source_iter first, PairWise::source_iter last)
: first{first}
, last{last}
, current{first}
{
}
friend bool operator==(const IterState& a, const IterState& b) {
// std::cout << "operator==(a,b)" << std::endl;
return (a.first == b.first)
&& (a.last == b.last)
&& (a.current == b.current);
}
IterState& operator++() {
// std::cout << "operator++()" << std::endl;
if (std::distance(current,last) >= 2) {
current++;
current++;
}
return *this;
}
const PairWise::value_type operator*() const {
// std::cout << "operator*()" << std::endl;
return std::make_tuple(*current, *(current+1));
}
};
using iterator = IterState;
using const_iterator = const IterState;
const_iterator cbegin() const {
return IterState{first,last};
}
const_iterator cend() const {
auto i = IterState{first,last};
i.current = last;
return i;
}
const_iterator begin() const {
// std::cout << "begin()" << std::endl;
return IterState{first,last};
}
const_iterator end() const {
// std::cout << "end()" << std::endl;
auto i = IterState{first,last};
i.current = last;
return i;
}
source_iter first;
source_iter last;
};
std::ostream& operator<<(std::ostream& os, const std::tuple<double,double>& value) {
auto [a,b] = value;
os << "<" << a << "," << b << ">";
return os;
}
template <class Container>
auto pairwise( const Container& container)
-> PairWise<typename Container::const_iterator>
{
return PairWise(container.cbegin(), container.cend());
}
int main( int argc, const char* argv[]) {
using VecF64_t = std::vector<double>;
VecF64_t data{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
for (const auto x : pairwise(data)) {
std::cout << x << std::endl;
}
return 0;
}
Elements in vector are stored in contiguous memory area, so you can use simple pointer arithmetics to access pair of doubles.
operator++ for iterator should skip 2 doubles at every use.
operator* can return tuple of references to double values, so you can read (pair = *it) or edit values (*it = pair).
struct Cont {
std::vector<double>& v;
Cont(std::vector<double>& v) : v(v) {}
struct Iterator : public std::iterator<std::input_iterator_tag , std::pair<double,double>> {
double* ptrData = nullptr;
Iterator(double* data) : ptrData(data) {}
Iterator& operator++() { ptrData += 2; return *this; }
Iterator operator++(int) { Iterator copy(*this); ptrData += 2; return copy; }
auto operator*() { return std::tie(*ptrData,*(ptrData+1)); }
bool operator!=(const Iterator& other) const { return ptrData != other.ptrData; }
};
auto begin() { return Iterator(v.data()); }
auto end() { return Iterator(v.data()+v.size());}
};
int main() {
std::vector<double> v;
v.resize(4);
Cont c(v);
for (auto it = c.begin(); it != c.end(); it++) {
*it = std::tuple<double,double>(20,30);
}
std::cout << v[0] << std::endl; // 20
std::cout << v[1] << std::endl; // 30
}
Demo
There's not an easy "C++" way to do this that's clean and avoids a copy of the original array. There's always this (make a copy):
vector<double> A; // your original list of points
vector<pair<double,double>> points;
for (size_t i = 0; i < A.size()/2; i+= 2)
{
points[i*2] = pair<double,double>(A[i], A[i+1]);
}
The following would likely work, violates a few standards, and the language lawyers will sue me in court for suggesting it. But if we can assume that the sizeof(XY) is the size of two doubles, has no padding, and expected alignment then cheating with a cast will likely work. This assumes you don't need a std::pair
Non standard stuff ahead
vector<double> A; // your original list of points
struct XY {
double x;
double y;
};
static_assert(sizeof(double)*2 == sizeof(XY));
static_assert(alignof(double) == alignof(XY));
XY* points = reinterpret_cast<XY*>(A.data());
size_t numPoints = A.size()/2;
// iterate
for (size_t i = 0; i < numPoints; i++) {
XY& point = points[i];
cout << point.x << "," << point.y << endl;
}
If you can guarantee that std::vector will always have an even number of entries, you could exploit the fact that an vector of doubles will have the same memory layout as a vector of pairs of doubles. This is kind of a dirty trick though so I wouldn't recommend it if you can avoid it. The good news is that the standard guarantees that vector elements will be contiguous.
inline const std::vector<std::pair<double, double>>& make_dbl_pair(std::vector<double>& v)
{
return reinterpret_cast<std::vector<std::pair<double, double>>&>(v);
}
This will only work for iteration with iterators. The size is likely to be double the number of pairs in the vector because it is still a vector of doubles underneath.
Example:
int main(int argc, char* argv[])
{
std::vector<double> dbl_vec = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 };
const std::vector<std::pair<double, double>>& pair_vec = make_dbl_pair(dbl_vec);
for (auto it = pair_vec.begin(); it != pair_vec.end(); ++it) {
std::cout << it->first << ", " << it->second << "\n";
}
std::cout << "Size: " << dbl_vec.size() << "\n";
return 0;
}

Sort just one member of the classes in a vector, leaving the other members unchanged

There are tons of answers for sorting a vector of struct in regards to a member variable. That is easy with std::sort and a predicate function, comparing the structs member. Really easy.
But I have a different question. Assume that I have the following struct:
struct Test {
int a{};
int b{};
int toSort{};
};
and a vector of that struct, like for example:
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
I do not want to sort the vectors elements, but only the values in the member variable. So the expected output should be equal to:
std::vector<Test> tvSorted{ {1,1,5},{2,2,6},{3,3,7},{4,4,8},{5,5,9} };
I wanted to have the solution to be somehow a generic solution. Then I came up with a (sorry for that) preprocessor-macro-solution. Please see the following example code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Test {
int a{};
int b{};
int toSort{};
};
#define SortSpecial(vec,Struct,Member) \
do { \
std::vector<decltype(Struct::Member)> vt{}; \
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [](const Struct& s) {return s.Member; }); \
std::sort(vt.begin(), vt.end()); \
std::for_each(vec.begin(), vec.end(), [&vt, i = 0U](Struct & s) mutable {s.Member = vt[i++]; }); \
} while (false)
int main()
{
// Define a vector of struct Test
std::vector<Test> tv{ {1,1,9},{2,2,8},{3,3,7},{4,4,6},{5,5,5} };
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
// Call sort macro
SortSpecial(tv, Test, toSort);
std::cout << "\n\nSorted\n";
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
Since macros shouldn't be used in C++, here my questions:
1. Is a solution with the algorithm library possible?
2. Or can this be achieved via templates?
To translate your current solution to a template solution is fairly straight forward.
template <typename T, typename ValueType>
void SpecialSort(std::vector<T>& vec, ValueType T::* mPtr) {
std::vector<ValueType> vt;
std::transform(vec.begin(), vec.end(), std::back_inserter(vt), [&](const T& s) {return s.*mPtr; });
std::sort(vt.begin(), vt.end());
std::for_each(vec.begin(), vec.end(), [&, i = 0U](T& s) mutable {s.*mPtr = vt[i++]; });
}
And we can call it by passing in the vector and a pointer-to-member.
SpecialSort(tv, &Test::toSort);
Somewhow like this (You just need to duplicate, rename and edit the "switchToShort" funtion for the rest of the variables if you want):
#include <iostream>
#include <vector>
struct Test {
int a{};
int b{};
int toSort{};
};
void switchToShort(Test &a, Test &b) {
if (a.toSort > b.toSort) {
int temp = a.toSort;
a.toSort = b.toSort;
b.toSort = temp;
}
}
//void switchToA(Test& a, Test& b) { ... }
//void switchToB(Test& a, Test& b) { ... }
inline void sortMemeberValues(std::vector<Test>& data, void (*funct)(Test&, Test&)) {
for (int i = 0; i < data.size(); i++) {
for (int j = i + 1; j < data.size(); j++) {
(*funct)(data[i], data[j]);
}
}
}
int main() {
std::vector<Test> tv { { 1, 1, 9 }, { 2, 2, 8 }, { 3,3 ,7 }, { 4, 4, 6 }, { 5, 5, 5} };
sortMemeberValues(tv, switchToShort);
//sortMemeberValues(tv, switchToA);
//sortMemeberValues(tv, switchToB);
for (const Test& t : tv) std::cout << t.a << " " << t.b << " " << t.toSort << "\n";
}
With range-v3 (and soon ranges in C++20), you might simply do:
auto r = tv | ranges::view::transform(&Test::toSort);
std::sort(r.begin(), r.end());
Demo

How can I skip the first iteration of range-based for loops?

I would like to do something like this:
for (int p : colourPos[i+1])
How do I skip the first iteration of my colourPos vector?
Can I use .begin() and .end()?
Since C++20 you can use the range adaptor std::views::drop from the Ranges library together with a range-based for loop for skipping the first element, as follows:
std::vector<int> colourPos { 1, 2, 3 };
for (int p : colourPos | std::views::drop(1)) {
std::cout << "Pos = " << p << std::endl;
}
Output:
Pos = 2
Pos = 3
Code on Wandbox
Note: I would not recommend using a solution that contains begin() and/or end(), because the idea of a range-based for loop is to get rid of iterators. If you need iterators, then I would stick with an interator-based for loop.
Live demo link.
#include <iostream>
#include <vector>
#include <iterator>
#include <cstddef>
template <typename T>
struct skip
{
T& t;
std::size_t n;
skip(T& v, std::size_t s) : t(v), n(s) {}
auto begin() -> decltype(std::begin(t))
{
return std::next(std::begin(t), n);
}
auto end() -> decltype(std::end(t))
{
return std::end(t);
}
};
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : skip<decltype(v)>(v, 1))
{
std::cout << p << " ";
}
}
Output:
2 3 4
Or simpler:
Yet another live demo link.
#include <iostream>
#include <vector>
template <typename T>
struct range_t
{
T b, e;
range_t(T x, T y) : b(x), e(y) {}
T begin()
{
return b;
}
T end()
{
return e;
}
};
template <typename T>
range_t<T> range(T b, T e)
{
return range_t<T>(b, e);
}
int main()
{
std::vector<int> v{ 1, 2, 3, 4 };
for (auto p : range(v.begin()+1, v.end()))
{
std::cout << p << " ";
}
}
Output:
2 3 4
Do this:
bool first = true;
for (int p : colourPos)
{
if (first)
{ first = false; continue; }
// ...
}

Negate boost range filtered adaptor

Is it possible/achievable to negate a boost filtered adaptor, e.g.
std::vector<int> v = {1, 2, 3, 4, 5};
for(auto i : v | !filtered(is_even))
std::cout << i << std::endl; // prints 1,3,5
instead of doing the negation inside the lambda expression?
Motivation: I work a lot with filtered and lambda functions, however when I use a filter more than once I usually refactor it into a custom filter, e.g.
for(auto i : v | even) // note: my filters are more complex than even.
std::cout << i << std::endl; // prints 2,4
Right now when I need the negation I am building a custom filter for them, e.g.
for(auto i : v | not_even)
std::cout << i << std::endl; // prints 1,2,3
but I would find it nicer to just be able to negate a filter, e.g.
for(auto i : v | !even)
std::cout << i << std::endl; // prints 1,2,3
Here's what I came up with on short notice:
#include <boost/range/adaptors.hpp>
#include <boost/functional.hpp>
#include <iostream>
namespace boost {
namespace range_detail {
template <typename T>
auto operator!(filter_holder<T> const& f) -> decltype(adaptors::filtered(boost::not1(f.val)))
{
return adaptors::filtered(boost::not1(f.val));
}
}
}
int main()
{
using namespace boost::adaptors;
int const v[] = { 1, 2, 3, 4 };
std::function<bool(int)> ll = [](int i){return 0 == (i%2);}; // WORKS
// bool(*ll)(int) = [](int i){return 0 == (i%2);}; // WORKS
// auto ll = [](int i){return 0 == (i%2);}; // not yet
auto even = filtered(ll);
for (auto i : v | !even)
{
std::cout << i << '\n';
}
}
See it live on liveworkspace.org
Note that it currently handles predicates of the form function pointer and std::function<...>, but not naked lambdas yet (on GCC 4.7.2)
This doesn't excactly answer the question, because it doesn't negate the filter, but only the predicate. I'm still posting this, because searching for the solution brought this question up as the first result.
Compared to the other answer, this has the advantage that we don't need to add custom code to namespace boost::range_detail.
C++17 Solution
The function std::not_fn can be used to create a negated predicate.
#include <boost/range/adaptors.hpp>
#include <functional>
#include <iostream>
struct is_even
{
bool operator()( int x ) const { return x % 2 == 0; }
};
int main()
{
using namespace boost::adaptors;
int const v[] = { 1, 2, 3, 4 };
for( auto i : v | filtered( std::not_fn( is_even{} ) ) )
{
std::cout << i << ' ';
}
}
Live Demo
C++11, C++14 Solution
The function std::not1 can be used to create a negated predicate. It has the additional requirement, that the predicate must define a member type, argument_type which has the same type as the predicates operator() parameter.
#include <boost/range/adaptors.hpp>
#include <functional>
#include <iostream>
struct is_even
{
using argument_type = int;
bool operator()( int x ) const { return x % 2 == 0; }
};
int main()
{
using namespace boost::adaptors;
int const v[] = { 1, 2, 3, 4 };
for( auto i : v | filtered( std::not1( is_even{} ) ) )
{
std::cout << i << ' ';
}
}
Live Demo