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
Is there any way to write a generic loop whcih iterates over values of both say stl map (associative container) and list (non associateve container).
template<typename T>
void foo(T &t)
{
for (auto iter = t.begin(); iter != t.end(); ++iter)
{
printf("%d\n", *iter); // will work for std::list<int> but not for std::map<int, int>
}
}
Thanks
To make it work for std::map - use proper adapter from boost:
foo(someMap | boost::adaptors::map_values);
You might also use Eric Niebler's ranges-v3
foo(someMap | ranges::values);
If you cannot use boost/ranges - use some kind of traits:
template <typename ValueType>
struct ValueGetter
{
static Value& get(ValueType& value)
{
return value;
}
};
template <typename Key, typename Value>
struct ValueGetter<std::pair<const Key, Value>>
{
using ValueType = std::pair<const Key, Value>;
static Value& get(ValueType& value)
{
return value.second;
}
};
template <typename ValueType>
auto& getValue(ValueType& value)
{
return ValueGetter<Value>::get(value);
}
template<typename T>
void foo(T &t)
{
for (auto iter = t.begin(); iter != t.end(); ++iter)
{
printf("%d\n", getValue(*iter));
}
}
Actually, there is already std::for_each (#include <algorithm>) for such purposes. You could feed it with appropriate handler, e. g. in the form of a lambda:
std::vector<int> v;
std::map<int, double> m;
std::for_each(v.begin(), v.end(), [](auto i) { printf("%d\n", i); });
std::for_each(m.begin(), m.end(), [](auto const& i) { printf("%d %f\n", i.first, i.second); });
I do like the way how Aconcagua show it and in most cases, this would be my favorite choice.
To make it more clear and fill the gap about my comment. The author's loop posted here is ok. In this case, the only problematic thing was about the printf(). To solve it, I have suggested something like overloading stream operator() to be able to print out std::map
ostream& operator<<(ostream& os, pair<string, int> it){
os << it.first << " => " << it.second;
}
as you might have realized the iterator in case of the std::map is the pair. Notice, you do not need to specify that for the std::list and the generic loop might look like the following
template<typename T>
void foo(T &t){
for(auto it=t.begin(); it=t.end(); ++it){
cout << *it << endl;
}
}
which is just fine with what was in the question, except printf() => cout. Here, you can also use range-based loops
template<typename T>
void foo(T &t){
for(auto it : t)
cout << it << endl;
}
and finally for_each() on the side with functor or lambda expression.
Sorry for the unclear question. I need to use the following template to sort an array of object belonging to a custom class using the insertion algorithm:
template<typename pointer, typename T, typename Functype>
void sort_array(pointer puntatore, T* obj, int dim, Functype pred){
T val;
for(int i=1; i<dim; i++){
val=obj[i];
for(int j=(i-1); j>=0; j--){
if(pred(obj[j].*puntatore, val.*puntatore)){
obj[j+1]=obj[j];
obj[j]=val;
}
}
}
}
I'm wondering how I can write a more general template that can accept any kind of iterator that points to an object of class T, not just a pointer. Writing T obj in parameter list gives me troubles with the variable T val in the assignment, which in this case would be something like *val=obj[i] being val itself an iterator. Is there any way to tell the template he has to take a generic iterator pointing to an object of class T(i.e. in the same way writing T* tells it to expect a pointer to an object of class T)?
example of how i might use this template
class Example{
int first;
int second;
};
template<typename pointer, typename T, typename Functype>
void sort_array(pointer puntatore, T* obj, int dim, Functype pred){
T val;
for(int i=1; i<dim; i++){
val=obj[i];
for(int j=(i-1); j>=0; j--){
if(pred(obj[j].*puntatore, val.*puntatore)){
obj[j+1]=obj[j];
obj[j]=val;
}
}
}
}
int main(){
Example array[5]={{1,2},{2,4},{1,7},{5,3},{6,7}};
//now i sort the elements in the array by their first element in a decreasing order
sort_array(&Example::first, array, 5, [](int a, int b){return (a<b);});
}
Well you could take inspiration from STL implementations and provide an interface that would take a range instead of an array like below:
template<typename BidirectionalIterator, typename Predicate =
std::less<typename std::iterator_traits<BidirectionalIterator>::value_type>>
void
insertion_sort(BidirectionalIterator first, BidirectionalIterator last,
Predicate pred = {}) {
if(first != last) {
auto it = first;
while(++it != last) {
auto it2 = it;
while(it2 != first) {
auto it3 = it2;
--it3;
if(pred(*it2, *it3)) {
std::swap(*it2, *it3);
} else {
break;
}
--it2;
}
}
}
}
Live Demo
Mind however, that you could also provide overloaded operator< or operator> for your objects for this to work with standard predicates:
bool
operator<(T const &A, T const &B) {
return A.*puntatore < B.*puntatore;
}
bool
operator>(T const &A, T const &B) {
return A.*puntatore < B.*puntatore;
}
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
}