Related
Is there any way to receive any iterable container as a parameter?
I would like a function to be able to receive any container while being able to begin() and end() on it. Unless I am wrong, every container should have these functions (std::view does not?).
Specifically, is there a way to receive a Container as an argument?
C++20 and/or tempates are fine.
void do_stuff(any_iterable_collection<int> &coll) {
for (auto it = coll.begin() ; it != coll.end() ; ++it) {
// do stuff with *it
}
}
std::list<int> list;
std::vector<int> vector;
std::set<int> set;
do_stuff(list);
do_stuff(vector);
do_stuff(set);
You can simply use the same way the standard perform this action:
template <typename Iterator>
void do_stuff(Iterator first, Iterator last) {
for (auto it = first; it != last; it = std::next(it)) {
// do stuff with *it
}
}
int main() {
std::vector<int> vec = {1, 5, 9};
do_stuff(vec.begin(), vec.end());
return EXIT_SUCCESS;
}
If you insist on the container:
template <template<typename> class Container>
void do_stuff(Container<int> &container) {
for (auto it = std::begin(container); it != std::end(container); it = std::next(it)) {
// do stuff with *it
std::cout << *it << std::endl;
}
}
Or for more generally container:
template <template<typename> class Container, typename CType>
void do_stuff(Container<CType> &container) {
for (auto it = std::begin(container); it != std::end(container); it = std::next(it)) {
// do stuff with *it
std::cout << *it << std::endl;
}
}
A simplified c++20 concept based on your requirements:
#include <concepts>
template <typename C, typename T>
concept any_iterable_collection =
std::same_as<typename C::value_type, T> &&
requires (C c) {
{ c.begin() } -> std::forward_iterator;
{ c.end() } -> std::forward_iterator;
{ const_cast<const C&>(c).begin() } -> std::forward_iterator;
{ const_cast<const C&>(c).end() } -> std::forward_iterator;
};
Usage:
void do_stuff(const any_iterable_collection<int> auto& coll);
DEMO
I'm working on big codes for which performance matters. And one of the things I read is that raw loops should be avoided and replaced by for_each, range-based for loops, or STL algorithms etc etc. The problem is that in all (most) examples, everything looks adapted for the problem, i.e. for_each is shown with the cout routine *eye roll*.
In my case, the index inside the loop matters (unless you show me otherwise). For example, I want to create tables like this:
std::vector<double> vect1 (nmax), vect2 (nmax);
for (size_t i{0}; i < nmax; ++i) {
vect1[i] = f(i); // f is a routine defined somewhere else
vect2[i] = f(i)+2.0;
}
What I could use is the generate function with a lambda function and it would be something like this:
std::vector<double> vect1 (nmax), vect2 (nmax);
size_t count{0};
generate(vect1.begin(), vect1.end(), [&]() {return f(count++);});
count=0;
generate(vect2.begin(), vect2.end(), [&]() {return f(count++) + 2.0;});
But I’m not a big fan of that, because:
count exists until the end of the routine.
We see that with another function, I have to put back count to zero and generate another vector again. I have to track down all the count variables etc. With the for loop, I could just put it in the same loop.
With the for loop, the correspondence is seen easily. i is on the left and the right. With generate, I feel like it’s counting with a different variable on the left and the right, which means potential mistake.
I can only do count++, not ++count, which means copy of variables.
Of course, this is a simple example. But I would like to know if the generate() version is still better for this kind of things (code/performance/readability wise). Or maybe there’s a better way of doing it, and I’m open to all suggestions and comments.
Thanks!
I wrote an index range that lets me:
std::vector<double> vect1 (nmax), vect2 (nmax);
for (auto i : index_upto(nmax))
vect1[i] = f(i); // f is a routine defined somewhere else
vect2[i] = f(i)+2.0;
}
which eliminates the manual fenceposting but leaves the code otherwise unchanged.
This isn't all that hard. Write a pseudo-iterator that stores a T and returns a copy on unary *. It should support == and ++ (passing both into the stored T).
template<class T>
struct index_it {
T t;
index_it& operator++() { ++t; return *this; }
index_it operator++(int) { auto r = *this; ++*this; return r; }
friend bool operator==( index_it const& lhs, index_it const& rhs ) {
return lhs.t == rhs.t;
}
friend bool operator!=( index_it const& lhs, index_it const& rhs ) {
return lhs.t != rhs.t;
}
T operator*()const& { return t; }
T operator*()&& { return std::move(t); }
};
Next, write a range:
template<class It>
struct range {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
then compose the two.
template<class T>
using index_range = range<index_it<T>>;
template<class T>
index_range<T> make_index_range( T s, T f ) {
return {{std::move(s)}, {std::move(f)}};
}
index_range<std::size_t> index_upto( std::size_t n ) {
return make_index_range( std::size_t(0), n );
}
note that index_it is not an iterator, but works much like one. You could probably finish it and make it an input iterator; beyond that you run into problems as iterators expect backing containers.
Using a stateful lambda is not a good idea. You may be better off writing your own generate function that takes a function object receiving an iterator:
template<class ForwardIt, class Generator>
void generate_iter(ForwardIt first, ForwardIt last, Generator g) {
while (first != last) {
*first = g(first);
++first;
}
}
You can use it as follows:
generate_iter(vect1.begin(), vect1.end(), [&](const std::vector<double>::iterator& iter) {
auto count = std::distance(vect1.begin(), iter);
return f(count);
});
Demo.
We could use a mutable lambda...
#include <vector>
#include <algorithm>
double f(int x) { return x*2; }
int main()
{
constexpr int nmax = 100;
std::vector<double> vect1 (nmax), vect2 (nmax);
std::generate(vect1.begin(),
vect1.end(),
[count = int(0)]() mutable { return f(count++); });
std::generate(vect2.begin(),
vect2.end(),
[count = int(0)]() mutable { return f(count++) + 2.0; });
}
Another option (uses c++17 for template argument deduction):
template<class F>
struct counted_function
{
constexpr counted_function(F f, int start = 0, int step = 1)
: f(f)
, counter(start)
, step(step) {}
decltype(auto) operator()() {
return f(counter++);
}
F f;
int counter;
int step;
};
used as:
std::generate(vect2.begin(),
vect2.end(),
counted_function([](auto x) { return f(x) + 2.0; }));
And finally, just for fun, could write this:
generate(vect2).invoking(f).with(every<int>::from(0).to(nmax - 1));
...if we had written something like this...
#include <vector>
#include <algorithm>
#include <iterator>
double f(int x) { return x*2; }
template<class T> struct value_iter
{
using value_type = T;
using difference_type = T;
using reference = T&;
using pointer = T*;
using iterator_category = std::forward_iterator_tag;
friend bool operator==(value_iter l, value_iter r)
{
return l.current == r.current;
}
friend bool operator!=(value_iter l, value_iter r)
{
return !(l == r);
}
T const& operator*() const& { return current; }
value_iter& operator++() { ++current; return *this; }
T current;
};
template<class T> struct every
{
struct from_thing
{
T from;
struct to_thing
{
auto begin() const { return value_iter<T> { from };}
auto end() const { return value_iter<T> { to+1 };}
T from, to;
};
auto to(T x) { return to_thing { from, x }; }
};
static constexpr auto from(T start)
{
return from_thing { start };
}
};
template<class F>
struct counted_function
{
constexpr counted_function(F f, int start = 0, int step = 1)
: f(f)
, counter(start)
, step(step) {}
decltype(auto) operator()() {
return f(counter++);
}
F f;
int counter;
int step;
};
template <class Container> struct generate
{
generate(Container& c) : c(c) {}
template<class F>
struct invoking_thing
{
template<class Thing>
auto with(Thing thing)
{
using std::begin;
using std::end;
std::copy(begin(thing), end(thing), begin(c));
return c;
}
F f;
Container& c;
};
template<class F>
auto invoking(F f) { return invoking_thing<F>{f, c}; }
Container& c;
};
int main()
{
constexpr int nmax = 100;
std::vector<double> vect2 (nmax);
generate(vect2).invoking(f).with(every<int>::from(0).to(nmax - 1));
}
With range-v3, it would be something like:
auto vect1 = ranges::view::ints(0, nmax) | ranges::view::transform(f);
auto vect2 = ranges::view::ints(0, nmax) | ranges::view::transform(f2);
// or auto vect2 = vect1 | ranges::view::transform([](double d){ return d + 2.; });
Demo
I need to have a while loop that applies a logic condition to every element of a vector.
For example, while(all elements < 3) or while(all elements != 3)
The only way I can think of is write while(vector[1]!=3 || vector[2]!=3 || ...). That would quickly grow if my vector is large.
Are there better way of doing this in C++?
See std::all_of
Assuming
std::vector<int> v;
if(std::all_of(v.cbegin(), v.cend(), [](int i){ return i < 3 }))
{
}
if(std::all_of(v.cbegin(), v.cend(), [](int i){ return i != 3 }))
{
}
Pre-C++11
struct Check
{
int d;
Check(int n) : d(n) {}
bool operator()(int n) const
{ return n < d; }
};
// Copied from above link
template< class InputIt, class UnaryPredicate >
bool all_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first) {
if (!p(*first)) {
return false;
}
}
return true ;
}
if( all_of(v.begin(), v.end(), Check(3) ))
{
}
In C++11, the answer is essentially using std::all together with lambdas:
if (std::all(v.begin(),v.end(),[](const typename std::decay::type& a)
{ return a<3; })
{ 7* your stuff here */ }
In C++03, you have to workout std::all and the lambdas:
template<class Iter, Fn>
bool all(Iter i, Iter end, Fn fn)
{
for(;i!=end; ++i)
if(!fn(*i)) return false;
return true;
}
and for <3 you need an explicit class like
class is_less_than_val
{
int val;
public:
is_less_than(int value) :val(value) {}
bool operator()(int var) const { return var<val; }
};
so that you can write
if(all(v.begin(),v.end(),is_less_than_val(3))
{ /* your stuff here */ }
In case you find all the functinal machinery obscure (C++03 is not that "easy", having no substantial type deduction), and prefer a more procedural approach,
template<class Cont, class Val>
bool all_less_than(const Cont& c, const Val& v)
{
for(typename Cont::const_iterator i=c.cbegin(), i!=c.end(); ++i)
if(!(*i < v)) return false;
return true;
}
template<class Cont, class Val>
bool all_equal_to(const Cont& c, const Val& v)
{
for(typename Cont::const_iterator i=c.cbegin(), i!=c.end(); ++i)
if(!(*i == v)) return false;
return true;
}
In all the samples, whatever the code is arranged, everything boils down into a loop that breaks as false on the negation of the searched condition.
Of course, if all are numerical comparison, !(<) is >= and !(==) is !=, but since Cont and Val are template parameters, using only < and == result is less requirements for Val implementation (that can be anything, not just int)
As others have said, in C++11, there are special functions for
this. In pre-C++11, the usual idiom would have involved
std::find_if, and a comparison with the end iterator on the
results, e.g.:
struct Condition
{
// The condition here must be inversed, since we're looking for elements
// which don't meet it.
bool operator()( int value ) const { return !(value < 3); }
};
// ...
while ( std::find_if( v.begin(), v.end(), Condition() ) == v.end() ) {
// ...
}
This is such a common idiom that I continue to use it in C++11
(although often with a lambda).
I have the following code (compiler: MSVC++ 10):
std::vector<float> data;
data.push_back(1.0f);
data.push_back(1.0f);
data.push_back(2.0f);
// lambda expression
std::for_each(data.begin(), data.end(), [](int value) {
// Can I get here index of the value too?
});
What I want in the above code snippet is to get the index of the value in the data vector inside the lambda expression. It seems for_each only accepts a single parameter function. Is there any alternative to this using for_each and lambda?
In C++14 thanks to generalized lambda captures you can do something like so:
std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [idx = 0] (int i) mutable {
// your code...
++idx; // 0, 1, 2... 9
});
Alternatively, you can use &value - &data[0], although it might be a bit more expensive.
std::for_each(data.begin(), data.end(), [&data](float const& value) {
int idx = &value - &data[0];
});
I don't think you can capture the index, but you can use an outer variable to do the indexing, capturing it into the lambda:
int j = 0;
std::for_each(data.begin(), data.end(), [&j](float const& value) {
j++;
});
std::cout << j << std::endl;
This prints 3, as expected, and j holds the value of the index.
If you want the actual iterator, you maybe can do it similarly:
std::vector<float>::const_iterator it = data.begin();
std::for_each(data.begin(), data.end(), [&it](float const& value) {
// here "it" has the iterator
++it;
});
Something like this:
template <typename IteratorT, typename FunctionT>
FunctionT enumerate(IteratorT first,
IteratorT last,
typename std::iterator_traits<IteratorT>::difference_type initial,
FunctionT func)
{
for (;first != last; ++first, ++initial)
func(initial, *first);
return func;
}
Used as:
enumerate(data.begin(), data.end(), 0, [](unsigned index, float val)
{
std::cout << index << " " << val << std::endl;
});
I think that the simplest way is to use std::accumulate:
std::accumulate(data.begin(), data.end(), 0, [](int index, float const& value)->int{
...
return index + 1;
});
This solution works with any container and it don't require a variable or custom classes.
Another way to wrap iterators for enumerate:
Required headers:
#include <algorithm>
#include <iterator>
#include <utility>
Wrapping iterator:
template<class Iter, class Offset=int>
struct EnumerateIterator : std::iterator<std::input_iterator_tag, void, void, void, void> {
Iter base;
Offset n;
EnumerateIterator(Iter base, Offset n = Offset()) : base (base), n (n) {}
EnumerateIterator& operator++() { ++base; ++n; return *this; }
EnumerateIterator operator++(int) { auto copy = *this; ++*this; return copy; }
friend bool operator==(EnumerateIterator const& a, EnumerateIterator const& b) {
return a.base == b.base;
}
friend bool operator!=(EnumerateIterator const& a, EnumerateIterator const& b) {
return !(a == b);
}
struct Pair {
Offset first;
typename std::iterator_traits<Iter>::reference second;
Pair(Offset n, Iter iter) : first (n), second(*iter) {}
Pair* operator->() { return this; }
};
Pair operator*() { return Pair(n, base); }
Pair operator->() { return Pair(n, base); }
};
Enumerate overloads:
template<class Iter, class Func>
Func enumerate(Iter begin, Iter end, Func func) {
typedef EnumerateIterator<Iter> EI;
return std::for_each(EI(begin), EI(end), func);
}
template<class T, int N, class Func>
Func enumerate(T (&a)[N], Func func) {
return enumerate(a, a + N, func);
}
template<class C, class Func>
Func enumerate(C& c, Func func) {
using std::begin;
using std::end;
return enumerate(begin(c), end(c), func);
}
Copied test from James:
#include <array>
#include <iostream>
struct print_pair {
template<class Pair>
void operator()(Pair const& p) {
std::cout << p.first << ": " << p.second << "\n";
}
};
int main() {
std::array<float, 5> data = {1, 3, 5, 7, 9};
enumerate(data, print_pair());
return 0;
}
I don't include providing an offset here; though it's fully ready in EnumerateIterator to start at otherwise than 0. The choice left is what type to make the offset and whether to add overloads for the extra parameter or use a default value. (No reason the offset has to be the iterator's difference type, e.g. what if you made it some date related type, with each iteration corresponding to the next day?)
Roger Pate suggested in a comment to my other answer creating an iterator wrapper that performs the enumeration. Implementing it was a bit of a beating.
This iterator wrapper takes a forward iterator whose value type is T (called the "inner iterator") and transforms it into a forward iterator whose value type is a pair<int, T&>, where int is the distance type of the inner iterator.
This would be quite simple, except for two things:
The std::pair constructor takes its arguments by const reference so we can't initialize a data member of type T&; we'll have to create our own pair type for the iterator.
In order to support the correct semantics for the iterator, we need an lvalue (operator* needs to return a reference and operator-> needs to return a pointer), so the pair needs to be a data member of the iterator. Since it contains a reference, we'll need a way to "reset" it and we'll need it to be lazily initialized so that we can correctly handle end iterators. boost::optional<T> seems not to like it if T is not assignable, so we'll write our own simple lazy<T>.
The lazy<T> wrapper:
#include <new>
#include <type_traits>
// A trivial lazily-initialized object wrapper; does not support references
template<typename T>
class lazy
{
public:
lazy() : initialized_(false) { }
lazy(const T& x) : initialized_(false) { construct(x); }
lazy(const lazy& other)
: initialized_(false)
{
if (other.initialized_)
construct(other.get());
}
lazy& operator=(const lazy& other)
{
// To the best of my knowledge, there is no clean way around the self
// assignment check here since T may not be assignable
if (this != &other)
construct(other.get());
return *this;
}
~lazy() { destroy(); }
void reset() { destroy(); }
void reset(const T& x) { construct(x); }
T& get() { return reinterpret_cast< T&>(object_); }
const T& get() const { return reinterpret_cast<const T&>(object_); }
private:
// Ensure lazy<T> is not instantiated with T as a reference type
typedef typename std::enable_if<
!std::is_reference<T>::value
>::type ensure_t_is_not_a_reference;
void construct(const T& x)
{
destroy();
new (&object_) T(x);
initialized_ = true;
}
void destroy()
{
if (initialized_)
reinterpret_cast<T&>(object_).~T();
initialized_ = false;
}
typedef typename std::aligned_storage<
sizeof T,
std::alignment_of<T>::value
>::type storage_type;
storage_type object_;
bool initialized_;
};
The enumerating_iterator:
#include <iterator>
#include <type_traits>
// An enumerating iterator that transforms an iterator with a value type of T
// into an iterator with a value type of pair<index, T&>.
template <typename IteratorT>
class enumerating_iterator
{
public:
typedef IteratorT inner_iterator;
typedef std::iterator_traits<IteratorT> inner_traits;
typedef typename inner_traits::difference_type inner_difference_type;
typedef typename inner_traits::reference inner_reference;
// A stripped-down version of std::pair to serve as a value type since
// std::pair does not like having a reference type as a member.
struct value_type
{
value_type(inner_difference_type f, inner_reference s)
: first(f), second(s) { }
inner_difference_type first;
inner_reference second;
};
typedef std::forward_iterator_tag iterator_category;
typedef inner_difference_type difference_type;
typedef value_type& reference;
typedef value_type* pointer;
explicit enumerating_iterator(inner_iterator it = inner_iterator(),
difference_type index = 0)
: it_(it), index_(index) { }
enumerating_iterator& operator++()
{
++index_;
++it_;
return *this;
}
enumerating_iterator operator++(int)
{
enumerating_iterator old_this(*this);
++*this;
return old_this;
}
const value_type& operator*() const
{
value_.reset(value_type(index_, *it_));
return value_.get();
}
const value_type* operator->() const { return &**this; }
friend bool operator==(const enumerating_iterator& lhs,
const enumerating_iterator& rhs)
{
return lhs.it_ == rhs.it_;
}
friend bool operator!=(const enumerating_iterator& lhs,
const enumerating_iterator& rhs)
{
return !(lhs == rhs);
}
private:
// Ensure that the template argument passed to IteratorT is a forward
// iterator; if template instantiation fails on this line, IteratorT is
// not a valid forward iterator:
typedef typename std::enable_if<
std::is_base_of<
std::forward_iterator_tag,
typename std::iterator_traits<IteratorT>::iterator_category
>::value
>::type ensure_iterator_t_is_a_forward_iterator;
inner_iterator it_; //< The current iterator
difference_type index_; //< The index at the current iterator
mutable lazy<value_type> value_; //< Pair to return from op* and op->
};
// enumerating_iterator<T> construction type deduction helpers
template <typename IteratorT>
enumerating_iterator<IteratorT> make_enumerator(IteratorT it)
{
return enumerating_iterator<IteratorT>(it);
}
template <typename IteratorT, typename DifferenceT>
enumerating_iterator<IteratorT> make_enumerator(IteratorT it, DifferenceT idx)
{
return enumerating_iterator<IteratorT>(it, idx);
}
A test stub:
#include <algorithm>
#include <array>
#include <iostream>
struct print_pair
{
template <typename PairT>
void operator()(const PairT& p)
{
std::cout << p.first << ": " << p.second << std::endl;
}
};
int main()
{
std::array<float, 5> data = { 1, 3, 5, 7, 9 };
std::for_each(make_enumerator(data.begin()),
make_enumerator(data.end()),
print_pair());
}
This has been minimally tested; Comeau and g++ 4.1 both accept it if I remove the C++0x type traits and aligned_storage (I don't have a newer version of g++ on this laptop to test with). Please let me know if you find any bugs.
I'm very interested in suggestions about how to improve this. Specifically, I'd love to know if there is a way around having to use lazy<T>, either by using something from Boost or by modifying the iterator itself. I hope I'm just being dumb and that there's actually a really easy way to implement this more cleanly.
Following the standard convention for C and C++, the first element has index 0, and the last element has index size() - 1.
So you have to do the following;-
std::vector<float> data;
int index = 0;
data.push_back(1.0f);
data.push_back(1.0f);
data.push_back(2.0f);
// lambda expression
std::for_each(data.begin(), data.end(), [&index](float value) {
// Can I get here index of the value too?
cout<<"Current Index :"<<index++; // gets the current index before increment
});
You could also pass a struct as third argument to std::for_each and count the index in it like so:
struct myStruct {
myStruct(void) : index(0) {};
void operator() (float i) { cout << index << ": " << i << endl; index++; }
int index;
};
int main()
{
std::vector data;
data.push_back(1.0f);
data.push_back(4.0f);
data.push_back(8.0f);
// lambda expression
std::for_each(data.begin(), data.end(), myStruct());
return 0;
}
Maybe in the lambda function, pass it a int& instead of value int, so you'd have the address. & then you could use that to deduce your position from the first item
Would that work? I don't know if for_each supports references
Is there any existing iterator implementation (perhaps in boost) which implement some sort of flattening iterator?
For example:
unordered_set<vector<int> > s;
s.insert(vector<int>());
s.insert({1,2,3,4,5});
s.insert({6,7,8});
s.insert({9,10,11,12});
flattening_iterator<unordered_set<vector<int> >::iterator> it( ... ), end( ... );
for(; it != end; ++it)
{
cout << *it << endl;
}
//would print the numbers 1 through 12
I don't know of any implementation in a major library, but it looked like an interesting problem so I wrote a basic implementation. I've only tested it with the test case I present here, so I don't recommend using it without further testing.
The problem is a bit trickier than it looks because some of the "inner" containers may be empty and you have to skip over them. This means that advancing the flattening_iterator by one position may actually advance the iterator into the "outer" container by more than one position. Because of this, the flattening_iterator needs to know where the end of the outer range is so that it knows when it needs to stop.
This implementation is a forward iterator. A bidirectional iterator would also need to keep track of the beginning of the outer range. The flatten function templates are used to make constructing flattening_iterators a bit easier.
#include <iterator>
// A forward iterator that "flattens" a container of containers. For example,
// a vector<vector<int>> containing { { 1, 2, 3 }, { 4, 5, 6 } } is iterated as
// a single range, { 1, 2, 3, 4, 5, 6 }.
template <typename OuterIterator>
class flattening_iterator
{
public:
typedef OuterIterator outer_iterator;
typedef typename OuterIterator::value_type::iterator inner_iterator;
typedef std::forward_iterator_tag iterator_category;
typedef typename inner_iterator::value_type value_type;
typedef typename inner_iterator::difference_type difference_type;
typedef typename inner_iterator::pointer pointer;
typedef typename inner_iterator::reference reference;
flattening_iterator() { }
flattening_iterator(outer_iterator it) : outer_it_(it), outer_end_(it) { }
flattening_iterator(outer_iterator it, outer_iterator end)
: outer_it_(it),
outer_end_(end)
{
if (outer_it_ == outer_end_) { return; }
inner_it_ = outer_it_->begin();
advance_past_empty_inner_containers();
}
reference operator*() const { return *inner_it_; }
pointer operator->() const { return &*inner_it_; }
flattening_iterator& operator++()
{
++inner_it_;
if (inner_it_ == outer_it_->end())
advance_past_empty_inner_containers();
return *this;
}
flattening_iterator operator++(int)
{
flattening_iterator it(*this);
++*this;
return it;
}
friend bool operator==(const flattening_iterator& a,
const flattening_iterator& b)
{
if (a.outer_it_ != b.outer_it_)
return false;
if (a.outer_it_ != a.outer_end_ &&
b.outer_it_ != b.outer_end_ &&
a.inner_it_ != b.inner_it_)
return false;
return true;
}
friend bool operator!=(const flattening_iterator& a,
const flattening_iterator& b)
{
return !(a == b);
}
private:
void advance_past_empty_inner_containers()
{
while (outer_it_ != outer_end_ && inner_it_ == outer_it_->end())
{
++outer_it_;
if (outer_it_ != outer_end_)
inner_it_ = outer_it_->begin();
}
}
outer_iterator outer_it_;
outer_iterator outer_end_;
inner_iterator inner_it_;
};
template <typename Iterator>
flattening_iterator<Iterator> flatten(Iterator it)
{
return flattening_iterator<Iterator>(it, it);
}
template <typename Iterator>
flattening_iterator<Iterator> flatten(Iterator first, Iterator last)
{
return flattening_iterator<Iterator>(first, last);
}
The following is a minimal test stub:
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
// Generate some test data: it looks like this:
// { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 } }
std::vector<std::vector<int>> v(3);
int i(0);
for (auto it(v.begin()); it != v.end(); ++it)
{
it->push_back(i++); it->push_back(i++);
it->push_back(i++); it->push_back(i++);
}
// Flatten the data and print all the elements:
for (auto it(flatten(v.begin(), v.end())); it != v.end(); ++it)
{
std::cout << *it << ", ";
}
std::cout << "\n";
// Or, since the standard library algorithms are awesome:
std::copy(flatten(v.begin(), v.end()), flatten(v.end()),
std::ostream_iterator<int>(std::cout, ", "));
}
Like I said at the beginning, I haven't tested this thoroughly. Let me know if you find any bugs and I'll be happy to correct them.
I decided to "improve" a bit on the flattening iterator concept, though as noted by James you are stuck using Ranges (except for the inner most container), so I just used ranges through and through and thus obtained a flattened range, with an arbitrary depth.
First I used a building brick:
template <typename C>
struct iterator { using type = typename C::iterator; };
template <typename C>
struct iterator<C const> { using type = typename C::const_iterator; };
And then defined a (very minimal) ForwardRange concept:
template <typename C>
class ForwardRange {
using Iter = typename iterator<C>::type;
public:
using pointer = typename std::iterator_traits<Iter>::pointer;
using reference = typename std::iterator_traits<Iter>::reference;
using value_type = typename std::iterator_traits<Iter>::value_type;
ForwardRange(): _begin(), _end() {}
explicit ForwardRange(C& c): _begin(begin(c)), _end(end(c)) {}
// Observers
explicit operator bool() const { return _begin != _end; }
reference operator*() const { assert(*this); return *_begin; }
pointer operator->() const { assert(*this); return &*_begin; }
// Modifiers
ForwardRange& operator++() { assert(*this); ++_begin; return *this; }
ForwardRange operator++(int) { ForwardRange tmp(*this); ++*this; return tmp; }
private:
Iter _begin;
Iter _end;
}; // class ForwardRange
This is our building brick here, though in fact we could make do with just the rest:
template <typename C, size_t N>
class FlattenedForwardRange {
using Iter = typename iterator<C>::type;
using Inner = FlattenedForwardRange<typename std::iterator_traits<Iter>::value_type, N-1>;
public:
using pointer = typename Inner::pointer;
using reference = typename Inner::reference;
using value_type = typename Inner::value_type;
FlattenedForwardRange(): _outer(), _inner() {}
explicit FlattenedForwardRange(C& outer): _outer(outer), _inner() {
if (not _outer) { return; }
_inner = Inner{*_outer};
this->advance();
}
// Observers
explicit operator bool() const { return static_cast<bool>(_outer); }
reference operator*() const { assert(*this); return *_inner; }
pointer operator->() const { assert(*this); return _inner.operator->(); }
// Modifiers
FlattenedForwardRange& operator++() { ++_inner; this->advance(); return *this; }
FlattenedForwardRange operator++(int) { FlattenedForwardRange tmp(*this); ++*this; return tmp; }
private:
void advance() {
if (_inner) { return; }
for (++_outer; _outer; ++_outer) {
_inner = Inner{*_outer};
if (_inner) { return; }
}
_inner = Inner{};
}
ForwardRange<C> _outer;
Inner _inner;
}; // class FlattenedForwardRange
template <typename C>
class FlattenedForwardRange<C, 0> {
using Iter = typename iterator<C>::type;
public:
using pointer = typename std::iterator_traits<Iter>::pointer;
using reference = typename std::iterator_traits<Iter>::reference;
using value_type = typename std::iterator_traits<Iter>::value_type;
FlattenedForwardRange(): _range() {}
explicit FlattenedForwardRange(C& c): _range(c) {}
// Observers
explicit operator bool() const { return static_cast<bool>(_range); }
reference operator*() const { return *_range; }
pointer operator->() const { return _range.operator->(); }
// Modifiers
FlattenedForwardRange& operator++() { ++_range; return *this; }
FlattenedForwardRange operator++(int) { FlattenedForwardRange tmp(*this); ++*this; return tmp; }
private:
ForwardRange<C> _range;
}; // class FlattenedForwardRange
And apparently, it works
I arrive a little late here, but I have just published a library (multidim) to deal with such problem. The usage is quite simple: to use your example,
#include "multidim.hpp"
// ... create "s" as in your example ...
auto view = multidim::makeFlatView(s);
// view offers now a flattened view on s
// You can now use iterators...
for (auto it = begin(view); it != end(view); ++it) cout << *it << endl;
// or a simple range-for loop
for (auto value : view) cout << value;
The library is header-only and has no dependencies. Requires C++11 though.
you can make one using iterator facade in boost.
I wrote iterator product which you can use as a template perhaps:
http://code.google.com/p/asadchev/source/browse/trunk/work/cxx/iterator/product.hpp
In addition to the answer of Matthieu, you can automatically count the amount of dimensions of the iterable/container. But first we must set up a rule when something is an iterable/container:
template<class T, class R = void>
struct AliasWrapper {
using Type = R;
};
template<class T, class Enable = void>
struct HasValueType : std::false_type {};
template<class T>
struct HasValueType<T, typename AliasWrapper<typename T::value_type>::Type> : std::true_type {};
template<class T, class Enable = void>
struct HasConstIterator : std::false_type {};
template<class T>
struct HasConstIterator<T, typename AliasWrapper<typename T::const_iterator>::Type> : std::true_type {};
template<class T, class Enable = void>
struct HasIterator : std::false_type {};
template<class T>
struct HasIterator<T, typename AliasWrapper<typename T::iterator>::Type> : std::true_type {};
template<class T>
struct IsIterable {
static constexpr bool value = HasValueType<T>::value && HasConstIterator<T>::value && HasIterator<T>::value;
};
We can count the dimensions as follows:
template<class T, bool IsCont>
struct CountDimsHelper;
template<class T>
struct CountDimsHelper<T, true> {
using Inner = typename std::decay_t<T>::value_type;
static constexpr int value = 1 + CountDimsHelper<Inner, IsIterable<Inner>::value>::value;
};
template<class T>
struct CountDimsHelper<T, false> {
static constexpr int value = 0;
};
template<class T>
struct CountDims {
using Decayed = std::decay_t<T>;
static constexpr int value = CountDimsHelper<Decayed, IsIterable<Decayed>::value>::value;
};
We then can create a view wrapper, that contains a begin() and end() function.
template<class Iterable, int Dims>
class Flatten {
public:
using iterator = FlattenIterator<Iterable, Dims>;
private:
iterator _begin{};
iterator _end{};
public:
Flatten() = default;
template<class I>
explicit Flatten(I&& iterable) :
_begin(iterable),
_end(iterable)
{}
iterator begin() const {
return _begin;
}
iterator end() const {
return _end;
}
};
To make the creation of the object Flatten a bit easier, we define a helper function:
template<class Iterable>
Flatten<std::decay_t<Iterable>, CountDims<Iterable>::value - 1> flatten(Iterable&& iterable) {
return Flatten<std::decay_t<Iterable>, CountDims<Iterable>::value - 1>(iterable);
}
Usage:
std::vector<std::vector<int>> vecs = {{1,2,3}, {}, {4,5,6}};
for (int i : flatten(vecs)) {
// do something with i
}