C++ iterator_adapter over collection of vectors [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Flattening iterator
I have a vector of vectors of some type (say int). I would like to iterate
over the collection of elements in the vectors, pretty much like iterating
over a vector of ints.
I can implement something that does this but was wondering how to use boost's
iterator_adapter to do this.

Here is something I hacked up. It works and outputs the correct result, but has a lot of work to be done.
#include <boost/iterator/iterator_adaptor.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
template <typename Iter>
class flattening_iterator :
public boost::iterator_adaptor<
flattening_iterator<Iter>,
Iter,
typename Iter::value_type::iterator::value_type,
boost::forward_traversal_tag,
typename Iter::value_type::iterator::value_type
>
{
private:
using super_t = boost::iterator_adaptor<
flattening_iterator<Iter>,
Iter,
typename Iter::value_type::iterator::value_type,
boost::forward_traversal_tag,
typename Iter::value_type::iterator::value_type
>;
using inner_iterator = typename Iter::value_type::iterator;
public:
flattening_iterator(Iter it)
: super_t(it),
inner_begin(),
inner_end(),
outer_end(it)
{}
flattening_iterator(Iter begin, Iter end)
: super_t(begin),
inner_begin((*begin).begin()),
inner_end((*begin).end()),
outer_end(end)
{}
using value_type = typename Iter::value_type::iterator::value_type;
private:
friend class boost::iterator_core_access;
inner_iterator inner_begin;
inner_iterator inner_end;
Iter outer_end;
void increment()
{
if (this->base_reference() == outer_end)
return; // At the end
++inner_begin;
if (inner_begin == inner_end)
{
++this->base_reference();
inner_begin = (*this->base_reference()).begin();
inner_end = (*this->base_reference()).end();
}
}
value_type dereference() const
{
return *inner_begin;
}
};
template <typename Iter>
auto flatten(Iter it) -> flattening_iterator<Iter>
{
return flattening_iterator<Iter>(it);
}
template <typename Iter>
auto flatten(Iter begin, Iter end) -> flattening_iterator<Iter>
{
return flattening_iterator<Iter>(begin, end);
}
int main()
{
std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
for (auto i = flatten(v1.begin(), v1.end()); i != flatten(v1.end()); ++i)
{
std::cout << *i << ' ';
}
std::cout << std::endl;
std::vector<std::vector<std::string>> v2{{"Hello", "Print"}, {"Me", "Here"}};
std::copy(flatten(v2.begin(), v2.end()), flatten(v2.end()),
std::ostream_iterator<std::string>(std::cout, " "));
}

Related

passing template function to std::for_each

I am trying to write a simple template function that prints every element of some container, without using for loops. So far, I have
#include <iostream>
#include <vector>
#include <algorithm>
template <typename T> void print_with_space(T x){
std::cout << x << ' ';
}
template <typename T> void print_all(T beg, T end){
std::for_each(beg, end, print_with_space<int>);
std::cout << '\n';
}
int main(){
int a[] = {1, 2, 3};
std::vector<int> v(a, a+3);
print_all(v.begin(), v.end());
return 0;
}
The code compiles and runs, but only because I put print_with_space<int> inside the implementation of print_all. I would like to just have print_with_space there for obvious reasons, but then the code doesn't compile. How do I do this?
You can use:
std::for_each(beg, end, [](const typename T::value_type& value) {
print_with_space(value);
});
T is of type std::vector<>::iterator, which is a RandomAccessIterator. Every RandomAcessIterator has a underlying type, which is exposed by value_type.
So, if you pass std::vector<int>::iterator, std::vector<int>::iterator::value_type would be an int.
Now that you have the type, you can make a lambda, which will get executed for every iteration.
In C++14, you can even do:
//'auto' automatically deduces the type for you
std::for_each(beg, end, [](const auto& value) {
print_with_space(value);
});
Another option:
template <typename T> void print_all(T beg, T end) {
std::for_each(beg, end, print_with_space<decltype(*beg)>);
std::cout << '\n';
}
Alternative for C++03:
#include <iterator>
template <typename T> void print_all(T beg, T end)
{
typedef typename std::iterator_traits<T>::value_type val_t;
std::for_each(beg, end, print_with_space<val_t>);
std::cout << '\n';
}
The most flexible solution, which will work with all versions of c++, is to make print_with_space a function object.
This confers a number of advantages:
no need to specify template type at call site.
no need to fiddle around with manual type deduction.
partial specialisation can be achieved by having the functor defer to a templated free function.
Such as:
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
// basic implementation
template<class T> void impl_print_with_space(const T& x)
{
std::cout << x << ' ';
}
// what about special handling for strings?
template<class C, class Ch, class Alloc>
void impl_print_with_space(const std::basic_string<C, Ch, Alloc>& x)
{
std::cout << std::quoted(x) << ' ';
}
// functor
struct print_with_space
{
template<class T> void operator()(const T& x) const
{
impl_print_with_space(x);
}
};
template <typename Iter> void print_all(Iter beg, Iter end)
{
std::for_each(beg, end, print_with_space());
std::cout << '\n';
}
int main(){
int a[] = {1, 2, 3};
std::vector<int> v(a, a+3);
print_all(v.begin(), v.end());
auto b = std::vector<std::string> { "hello", "world" };
print_all(b.begin(), b.end());
return 0;
}

Specialize function for map like containers

I want specialize a function template for vector and map like containers. For vector I can do like below but I don't know how can I have a specialized version of the function that will be used only for map like containers.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
template<typename Iterator>
void print(Iterator begin, Iterator end)
{
while (begin != end)
{
cout << *begin << endl; // compiler error for map like containers
++begin;
}
}
int main()
{
vector<int> noVec = { 1, 2, 3 };
print(noVec.begin(), noVec.end());
map<int, int> nosMap;
nosMap[0] = 1;
nosMap[1] = 2;
nosMap[3] = 3;
print(nosMap.begin(), nosMap.end());
return 0;
}
This question is similar but it suggests to use pair in vector which I don't want to do. I know the specialization can be done with SFINAE but don't know what condition to check for. It would be great if I can achieve this with C++ 11 type_traits.
The value_type of a map is some pair so you could check if the value_type of the iterator is a std::pair or not, e.g.
#include <vector>
#include <map>
#include <iostream>
template <typename>
struct is_pair : std::false_type
{ };
template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type
{ };
template <typename Iter>
typename std::enable_if<is_pair<typename std::iterator_traits<Iter>::value_type>::value>::type
print(Iter begin, Iter end)
{
std::cout << "called with map-like" << std::endl;
for (; begin != end; ++begin)
{
std::cout << begin->second;
}
std::cout << std::endl;
}
template <typename Iter>
typename std::enable_if<!is_pair<typename std::iterator_traits<Iter>::value_type>::value>::type
print(Iter begin, Iter end)
{
std::cout << "called with vector-like" << std::endl;
for (; begin != end; ++begin)
{
std::cout << *begin;
}
std::cout << std::endl;
}
int main()
{
std::vector<int> vec { 1, 2, 3 };
std::map<int, int> map {{0, 0}, {1, 1}, {2, 4}, {3, 9}};
print(vec.begin(), vec.end());
print(map.begin(), map.end());
}
which prints
called with vector-like
123
called with map-like
0149
You don't need to specialize anything. All you have to do is to provide an overloaded output operator<< for std::pair, like the example below:
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream &out, std::pair<T1, T2> const &mp) {
return (out << "(" << mp.first << ", " << mp.second << ")");
}
LIVE DEMO
edit:
The above solution however as #Benjamin Lindley suggested in the comments might conflict with other template overloads of the output operator<< for std::pair.
If this is the case, alternatively you could write in their own namespace (e.g., namespace detail) two template function overloads (e.g., print_elem), like the example below:
namespace detail {
template<typename T1, typename T2>
std::ostream& print_elem(std::ostream &out, std::pair<T1, T2> const &mp) {
return (out << "(" << mp.first << ", " << mp.second << ")");
}
template<typename T>
std::ostream& print_elem(std::ostream &out, T const &elem) {
return (out << elem);
}
}
and change your template print like the example below:
template<typename Iterator>
void print(Iterator begin, Iterator end)
{
while (begin != end) {
detail::print_elem(cout, *begin) << endl;
++begin;
}
}
LIVE DEMO

Best way to emulate something like conditional_back_inserter?

I wanted to replace the loop with an algorithm in the following code
int numbers[] = { ... };
vector<int> output;
for( int* it = numbers+from; it != numbers+to ; ++it )
{
int square = func( *it );
if( predicate(square) )
{
output.push_back(square);
}
}
The program is meant to transform the values and copy them to a destination if a condition occurs.
I could not use std::copy_if because that would not apply a transformation.
I could not use std::transform because that lacks a predicate
It is not even a good idea to write a transform_copy_if() , because of the intermediate copy of the transformed variable.
It looks like my only hope is to create a conditional_back_insert_iterator. Then I could have a pretty decent call like:
int numbers[] = { ... };
vector<int> output;
std::transform(numbers+from, numbers+to,
conditional_back_inserter(predicate, output),
func);
Is this solution the best way to treat such cases ? I couldn't even google for conditional inserters, so I am worried I'm on the wrong path.
I could also imagine that I could implement an alternative solution such as
std::copy_if( transform_iterator<func>(numbers+from),
transform_iterator<func>(numbers+to),
back_inserter(output) );
(which reminds me of an example of *filter_iterators* in boost)
but that does not offer readability.
I think creating your own iterator is the way to go:
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
template<class T>
class conditional_back_insert_iterator
: public std::back_insert_iterator<std::vector<T>>
{
private:
using Base = std::back_insert_iterator<std::vector<T>>;
using Container = std::vector<T>;
using value_type = typename Container::value_type;
public:
template<class F>
conditional_back_insert_iterator(Container& other, F&& pred)
: Base(other), c(other), predicate(std::forward<F>(pred))
{ }
conditional_back_insert_iterator<T>& operator*()
{ return *this; }
conditional_back_insert_iterator<T>&
operator=(const value_type& val) const
{
if (predicate(val))
c.push_back(val);
return *this;
}
conditional_back_insert_iterator<T>&
operator=(value_type&& val) const
{
if (predicate(val))
c.push_back(std::move(val));
return *this;
}
private:
Container& c;
std::function<bool (const value_type&)> predicate;
};
template<
class Container,
class F,
class value_type = typename Container::value_type
>
conditional_back_insert_iterator<value_type>
conditional_back_inserter(Container& c, F&& predicate)
{
return conditional_back_insert_iterator<value_type>(c, std::forward<F>(predicate));
}
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> to;
auto is_even = [] (int x) { return (x % 2) == 0; };
std::copy(v.begin(), v.end(), conditional_back_inserter(to, is_even));
}
Here's my attempt.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
template <class Container, class Pred>
class conditional_insert_iterator
: public std::iterator< std::output_iterator_tag, void, void, void, void >
{
public:
explicit conditional_insert_iterator(Container& c, Pred p) : container(&c), pred(p) {}
conditional_insert_iterator& operator=(typename Container::const_reference value) {
if (pred(value))
container->push_back(value);
return *this;
}
conditional_insert_iterator& operator*() {return *this;}
conditional_insert_iterator& operator++() {return *this;}
conditional_insert_iterator& operator++(int) {return *this;}
private:
Container* container;
Pred pred;
};
template< class Container, class Pred>
conditional_insert_iterator<Container, Pred> conditional_inserter( Container& c, Pred pred )
{
return conditional_insert_iterator<Container, Pred>(c, pred);
}
using namespace std;
int main()
{
vector<int> in = { 1, 2, 3, 4, 5, 6 };
vector<int> out;
transform(in.begin(), in.end(),
conditional_inserter(out, [](int i) { return i%2 == 0;}),
[](int i) { return i + 2;});
for (auto i : out)
cout << i << "\n";
return 0;
}

Iterating over a range of ranges [duplicate]

This question already has answers here:
Flattening iterator
(5 answers)
Closed 8 years ago.
If I have a range of ranges, is there a way to join them together and iterate over them as if they were a single range?
By range, I mean any kind of container or iterator pair. Basically like boost's ranges. Boost already have a function for joining two ranges together with boost::join, but that function can't join an arbitary number of ranges.
Basically, I'm looking for a way to do what the the many function does in this piece of code:
std::vector<std::vector<int>> n = {{0, 1}, {2, 3}};
for (auto i : many(n))
std::cout << i << '\n';
Which would output 0, 1, 2, 3.
In C#, I had SelectMany which could do this.
Here is an example of a flattening iterator used with range-based for (taken from here and added boost::make_iterator_range to show range version) (still needs work though):
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/range.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
template <typename Iter>
class flattening_iterator :
public boost::iterator_adaptor<
flattening_iterator<Iter>,
Iter,
typename Iter::value_type::iterator::value_type,
boost::forward_traversal_tag,
typename Iter::value_type::iterator::value_type
>
{
private:
using super_t = boost::iterator_adaptor<
flattening_iterator<Iter>,
Iter,
typename Iter::value_type::iterator::value_type,
boost::forward_traversal_tag,
typename Iter::value_type::iterator::value_type
>;
using inner_iterator = typename Iter::value_type::iterator;
public:
flattening_iterator(Iter it)
: super_t(it),
inner_begin(),
inner_end(),
outer_end(it)
{}
flattening_iterator(Iter begin, Iter end)
: super_t(begin),
inner_begin((*begin).begin()),
inner_end((*begin).end()),
outer_end(end)
{}
using value_type = typename Iter::value_type::iterator::value_type;
private:
friend class boost::iterator_core_access;
inner_iterator inner_begin;
inner_iterator inner_end;
Iter outer_end;
void increment()
{
if (this->base_reference() == outer_end)
return; // At the end
++inner_begin;
if (inner_begin == inner_end)
{
++this->base_reference();
inner_begin = (*this->base_reference()).begin();
inner_end = (*this->base_reference()).end();
}
}
value_type dereference() const
{
return *inner_begin;
}
};
template <typename Iter>
auto flat_iter(Iter it) -> flattening_iterator<Iter>
{
return flattening_iterator<Iter>(it);
}
template <typename Iter>
auto flat_iter(Iter begin, Iter end) -> flattening_iterator<Iter>
{
return flattening_iterator<Iter>(begin, end);
}
template <typename Cont>
auto flatten(Cont& c) -> boost::iterator_range<flattening_iterator<decltype(std::declval<Cont>().begin())>>
{
return boost::make_iterator_range(flat_iter(c.begin(), c.end()), flat_iter(c.end()));
}
int main()
{
std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
for (auto i : flatten(v1))
{
std::cout << i << ' ';
}
}
Output
1 2 3 4 5 6 7 8 9

How to slice with for-range loop ? C++0x

Using range based for loops in C++0X, I know we'll be able to do :
std::vector<int> numbers = generateNumbers();
for( int k : numbers )
{
processNumber( k );
}
(might be even simpler to write with lambda)
But how should i do if I only want to apply processNumber( k ) to a part of numbers? For example, how should I write this for loop for to apply processNumber() to the half (head or tail) of the numbers? Is "slicing" allowed like in Python or Ruby?
You can use the "sliced" range adaptor from the Boost.Range library:
#include <boost/range/adaptor/sliced.hpp>
using boost::adaptors::sliced;
...
std::vector<int> numbers = generateNumbers();
for( int k : numbers | sliced(0, numbers.size() / 2))
{
processNumber( k );
}
One possibility might be boost's iterator_range
(Not having a compiler which supports range-based for, using BOOST_FOREACH instead. I'd expect range-based for work the same, as long as the container or range has the begin and end method.)
#include <boost/foreach.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
BOOST_FOREACH(int n, boost::make_iterator_range(v.begin(), v.begin() + v.size() / 2)) {
std::cout << n << '\n';
}
}
For convenience you could also make your own slice function, so it would accept indices instead of iterators. Again, it could be based on boost.iterator_range, or not:
#include <cstddef>
#include <iterator>
template <class Iterator>
class iter_pair
{
public:
typedef Iterator iterator;
typedef Iterator const_iterator; //BOOST_FOREACH appears to want this
iter_pair(iterator first, iterator last): first(first), last(last) {}
iterator begin() const { return first; }
iterator end() const { return last; }
private:
iterator first, last;
};
template <class Container>
struct iterator_type
{
typedef typename Container::iterator type;
};
template <class Container>
struct iterator_type<const Container>
{
typedef typename Container::const_iterator type;
};
template <class Container>
iter_pair<typename iterator_type<Container>::type>
slice(Container& c, size_t i_first, size_t i_last)
{
typedef typename iterator_type<Container>::type iterator;
iterator first = c.begin();
std::advance(first, i_first);
iterator last = first;
std::advance(last, i_last - i_first);
return iter_pair<iterator>(first, last);
}
template <class Container>
iter_pair<typename iterator_type<Container>::type>
slice(Container& c, size_t i_last)
{
return slice(c, 0, i_last);
}
//could probably also be overloaded for arrays
#include <cctype>
#include <string>
#include <boost/foreach.hpp>
#include <iostream>
int main()
{
std::string s("Hello world, la-la-la!");
BOOST_FOREACH( char& c, slice(s, 2, 11)) {
if (c == 'l')
c = std::toupper(c);
}
const std::string& r = s;
BOOST_FOREACH( char c, slice(r, r.size() - 1) ) {
std::cout << c << " ";
}
std::cout << '\n';
}
Generally one would probably be working with iterators in the first place, so it might not be that useful.
Something like this may work (unchecked as I don't have access to a C++0x compiler),
Edit: Checked it on VS10, of course I had to fix numurous errors....
Define a class which is a proxy to any container and whose iterators only return a subset of the container. The example I supply is the simplest one giving the first half but it can be made much more general.
template <class Container>
class head_t {
Container& c_;
public:
template <class T>
class iter {
T curr_;
const T& end_;
int limit_; // count how many items iterated
public:
iter(T curr, const T& end)
: curr_(curr)
, end_(end)
, limit_(std::distance(curr_, end_)/2)
{ }
typename Container::value_type operator*() { return *curr_; }
// Do the equivilant for for operator++(int)
iter& operator++() {
if (--limit_ == 0) // finished our slice
curr_ = end_;
else
++curr_;
return *this;
}
bool operator!=(const iter& i) const {
return curr_ != i.curr_;
}
};
head_t(Container& c) : c_(c) {}
iter<typename Container::iterator> begin() {
return iter<typename Container::iterator>(c_.begin(), c_.end());
}
iter<typename Container::iterator> end() {
return iter<typename Container::iterator>(c_.end(), c_.end());
}
};
template <class T>
head_t<T> head(T& t) { return head_t<T>(t); }
And then you use it in the loop:
for( int k : head(numbers) )