I want to write universal function that receives container1 with values [a1, .. , an] and returns another container2 with values [convert(a1), .. , convert(an)].
If container2 is std::vector, the problem is trivial, std::transform does exactly what I want. The following function can deal with arbitrary container2 and container1
template<class ToType, class FromType>
ToType convert(const FromType& from)
{
std::vector<typename ToType::value_type> tmp;
std::transform(from.begin(), from.end(),
std::back_inserter(tmp),
[](const typename FromType::value_type& f) {
return convert<typename ToType::value_type>(f);
});
return ToType(tmp.begin(), tmp.end());
}
But it does addition copy. Does anyone know how to do better?
Check out this answer to Is it possible to write a C++ template to check for a function's existence?. You can use SFINAE to detect if a function of your destination container exists (such as push_back or insert) or if an inserter for your container exists (such as inserter or back_inserter), and behave accordingly.
Another way is to create a fake iterator:
template <class T, class U>
struct ConvertIterator {
typedef T dest_type;
typedef U it_type;
ConvertIterator(U&& val) : iterator(std::forward<U>(val)) {
}
bool operator == (const ConvertIterator &other) const {
return iterator == other.iterator;
}
bool operator != (const ConvertIterator &other) const {
return iterator != other.iterator;
}
dest_type operator * () const {
return convert<dest_type>(*iterator);
}
ConvertIterator<T, U> & operator ++() {
++iterator;
return *this;
}
it_type iterator;
};
and then:
template<class ToType, class FromType>
ToType convert(const FromType& from)
{
typedef ConvertIterator<typename ToType::value_type, decltype(from.begin()) > convert_it;
return ToType(convert_it(from.begin()), convert_it(from.end()));
}
Here is a function-based converting iterator. It has all the proper typedefs for a forward iterator. We could upgrade it to support all of the tag properties of the incoming Base iterator type if we chose:
template<
class Base,
class F,
class R=typename std::result_of<F(decltype(*std::declval<Base const&>()))>::type
>
struct convert_iterator:
std::iterator<std::forward_iterator_tag,typename std::decay<R>::type>
{
Base it;
F f;
template<class It, class Func>
convert_iterator(It&&base, Func&&func):it(std::forward<It>(base)),
// defaulted stuff:
convert_iterator()=default;
convert_iterator(convert_iterator const&)=default;
convert_iterator(convert_iterator &&)=default;
convert_iterator& operator=(convert_iterator const&)=default;
convert_iterator& operator=(convert_iterator &&)=default;
bool operator==(convert_iterator const&other) const {
return it == other.it;
}
bool operator!=(convert_iterator const&other) const { return !(*this==other); }
// a bit overkill, but rvalue and lvalue overrides for these:
R operator*() const& {
return f(*it);
}
R operator*() & {
return f(*it);
}
R operator*() const&& {
return std::move(f)(*std::move(it));
}
R operator*() && {
return std::move(f)(*std::move(it));
}
// normal pre-increment:
convert_iterator& operator++()& {
++it;
return *this;
}
// pre-increment when we are guaranteed not to be used again can be done differently:
convert_iterator operator++()&& {
return {std::next(std::move(it)), std::forward<F>(f)};
}
// block rvalue post-increment like a boss:
convert_iterator operator++(int)& {
return {it++, f};
}
};
a helper function to create them:
template< class Base, class F >
convert_iterator<typename std::decay<Base>::type,typename std::decay<F>::type>
make_convert_iterator(Base&& b, F&& f) { return {std::forward<Base>(b), std::forward<F>(f)}; }
Next I create a class that handles conversion. Specialization lets us dispatch differently for containers and scalars:
// for scalars:
template<class ToType,class=void>
struct converter {
template<class FromType>
ToType operator()(FromType&& from)const{ return std::forward<FromType>(from); }
};
// attempt at SFINAE test for container:
template<class ToContainer>
struct converter<ToContainer, (void)(
typename std::iterator_traits<
typename std::decay<decltype(std::begin(std::declval<ToContainer&>())>::type
>::value_type
)>
{
using std::begin; using std::end;
using R=std::iterator_traits<typename std::decay<decltype(begin(std::declval<ToContainer&>()))>::type>::value_type;
template<class FromType, class T=decltype(*begin(std::declval<FromType>())>
ToContainer operator()(FromType&& from) const {
auto sub_convert = [](T&& t)->R{
return converter<R>{}(std::forward<T>(t));
};
return {
make_convert_iterator(begin(std::forward<From>(from)), sub_convert),
make_convert_iterator(end(std::forward<From>(from)), sub_convert)
};
};
};
The action convert function is now a one-liner:
template<class ToType>
ToType convert(FromType&& from)
{
return converter<ToType>{}(std::forward<FromType>(from));
}
Related
Why does this code work with the #if 0 block in place, but fails with a fairly complex set of error messages if you remove it? And more importantly, how do I make it the same result as the very similar block above it?
#include <ranges>
#include <iterator>
#include <optional>
#include <string_view>
#include <iostream>
#include <algorithm>
template <::std::ranges::view View,
typename Pred>
requires ::std::ranges::input_range<View> &&
::std::ranges::common_range<View> &&
::std::is_object_v<Pred> &&
::std::indirect_unary_predicate<const Pred, ::std::ranges::iterator_t<View>>
class skip_after_view : public ::std::ranges::view_interface<skip_after_view<View, Pred>>
{
public:
skip_after_view() = default;
skip_after_view(View v, Pred p)
: subview_(::std::move(v)), pred_(::std::move(p))
{}
class iterator;
friend class iterator;
auto begin() const {
return iterator{subview_.begin(), subview_.end(), &pred_};
}
auto end() const {
return iterator{subview_.end(), subview_.end(), &pred_};
}
private:
View subview_ = View();
Pred pred_;
};
template <typename View, typename Pred>
class skip_after_view<View, Pred>::iterator
{
using parent_t = View::iterator;
using parent_traits = ::std::iterator_traits<parent_t>;
friend class skip_after_view<View, Pred>;
public:
using value_type = parent_traits::value_type;
using reference = parent_traits::reference;
using pointer = parent_traits::pointer;
using difference_type = ::std::ptrdiff_t;
using iterator_category = ::std::input_iterator_tag;
constexpr iterator() = default;
auto operator *() { return *me_; }
auto operator *() const { return *me_; }
iterator &operator ++() {
for (bool last_pred = true; last_pred; ) {
if (end_ != me_) {
last_pred = (*pred_)(operator *());
++me_;
} else {
last_pred = false;
}
}
return *this;
}
void operator ++(int) {
++(*this);
}
friend
bool operator ==(iterator const &a, iterator const &b) {
return a.me_ == b.me_;
}
private:
parent_t me_;
parent_t end_;
Pred const *pred_ = nullptr;
iterator(parent_t const &me, parent_t end, Pred const *pred)
: me_(me), end_(::std::move(end)), pred_(pred)
{}
};
template <std::ranges::range Range, typename Pred>
skip_after_view(Range&&) -> skip_after_view<std::ranges::views::all_t<Range>, Pred>;
struct skip_after_adaptor {
template <typename Pred>
class closure {
friend class skip_after_adaptor;
Pred pred;
explicit closure(Pred &&p) : pred(::std::move(p)) {}
public:
template <typename Range>
auto operator ()(Range &&range) {
return skip_after_view(::std::forward<Range>(range),
::std::move(pred));
}
};
template <typename Pred>
auto operator ()(Pred pred) const {
return closure<Pred>(::std::move(pred));
}
template <typename Range, typename Pred>
auto operator()(Range &&range, Pred &&pred) const {
return skip_after_view(::std::forward(range), ::std::forward(pred));
}
template <typename Range, typename Pred>
friend auto operator|(Range&& rng, closure<Pred> &&fun) {
return fun(std::forward<Range>(rng));
}
};
constexpr auto skip_after = skip_after_adaptor{};
template <::std::input_iterator it>
void check(it const &)
{}
int main()
{
using ::std::string_view;
using namespace ::std::ranges::views;
using ::std::ostream_iterator;
using ::std::ranges::copy;
using ::std::cout;
auto after_e = [](char c) { return c == 'e'; };
constexpr string_view sv{"George Orwell"};
int sum = 0;
{
cout << '[';
copy(sv | skip_after(after_e) | take(6),
ostream_iterator<char>(cout));
cout << "]\n";
}
#if 0
{
auto tmp = skip_after(after_e) | take(6);
cout << '[';
copy(sv | tmp, ostream_iterator<char>(cout));
cout << "]\n";
}
#endif
return sum;
}
Obligatory Compiler Explorer link
If what I want isn't cleanly possible, is there an ugly way to do it? For example, could I make my own composition mechanism and have an ugly bunch of garbage to interface it with the existing views.
There's no way to write a range adapter closure object that composes with the standard ones in C++20. The standard library doesn't expose the mechanism it uses for that composition.
sv | skip_after(after_e) | take(6) works because sv | skip_after(after_e) hits your operator|, which produces a view that can then be used with take(6).
There's a good chance that C++23 will expose the composition mechanism.
I would like to implement an operator over vector that would skip a certain value. This is what I wrote, with the problem I am facing commented:
template<class MyVector>
struct VectorSkipConstIterator : MyVector::const_iterator {
using Base = typename MyVector::const_iterator;
using ValueType = typename MyVector::value_type;
VectorSkipConstIterator(const ValueType &skip) : Base(), skip_(skip){};
VectorSkipConstIterator(Base it_, const ValueType &skip)
: Base(it_), skip_(skip){};
VectorSkipConstIterator &operator++() {
do {
Base::operator++();
} while (/* have not reached the end */ && this->operator*() == skip_);
return *this;
}
private:
ValueType skip_;
};
So, the problem is that operator++ has to stop somewhere (namely, at the end) even if the last value(s) in the vector need to be skipped. How can this be achieved?
One possible way of achieving this is by simply passing the end iterator as an argument to VectorSkipConstIterator, and keeping it in a field.
template<class MyVector>
struct VectorSkipConstIterator : MyVector::const_iterator {
using Base = typename MyVector::const_iterator;
using ValueType = typename MyVector::value_type;
VectorSkipConstIterator(const ValueType &skip, Base end)
: Base(), skip_(skip){}, end_(end)
{
}
VectorSkipConstIterator(Base it_, const ValueType &skip, Base end)
: Base(it_), skip_(skip), end_(end)
{
}
VectorSkipConstIterator &operator++() {
do {
Base::operator++();
} while (*this != end_ && this->operator*() == skip_);
return *this;
}
private:
ValueType skip_;
Base end_;
};
As TartanLlama said in the comments, inheriting from an iterator is not a good idea. Consider implementing your own iterator class from scratch, satisfying the RandomAccessIterator concept.
Another possible (and in my opinion, better) way of achieving what you desire is using an higher-order function:
template <typename TContainer, typename TSkip, typename TF>
void forEachExcept(TContainer&& c, TSkip&& s, TF&& f)
{
for(auto&& x : c)
{
if(x != s) f(x);
}
}
You can use it as follows:
std::vector<int> v{1,2,5,1,6,2,1};
// skip all occurrences of `1`
forEachExcept(v, 1, [](auto x){ std::cout << x; });
// prints "2562"
In order to broaden my understanding of C++11, I'm experimenting with writing functional helpers and seeing if I can make calling them less verbose. Right now I'm trying to write a some function that returns true if any item in a collection passes a test. I want it to work with any collection type, be able to take any callable, and not require template arguments.
Essentially, I want it to work such that the following code will compile:
// insert declaration of some here
#include <list>
#include <functional>
class Foo {
public:
bool check() const { return true; };
};
class DerivedFooList : public std::list<Foo> {
public:
DerivedFooList(std::initializer_list<Foo> args) : std::list<Foo>(args) {};
};
class DerivedFooPtrList : public std::list<Foo *> {
public:
DerivedFooPtrList(std::initializer_list<Foo *> args) : std::list<Foo *>(args) {};
};
bool intCheck(int a) { return a == 1; }
bool fooCheck(const Foo &a) { return a.check(); }
bool fooPtrCheck(const Foo *a) { return a->check(); }
int main()
{
Foo a, b, c;
std::list<int> intList = {1, 2, 3};
std::list<Foo> fooList = {a, b, c};
std::list<Foo *> fooPtrList = {&a, &b, &c};
DerivedFooList derivedFooList = {a, b, c};
DerivedFooPtrList derivedFooPtrList = {&a, &b, &c};
auto localIntCheck = [] (int a) { return a == 1; };
auto localFooCheck = [] (const Foo &a) { return a.check(); };
auto localFooPtrCheck = [] (const Foo *a) { return a->check(); };
some(intList, [] (int a) { return a == 1; });
some(intList, &intCheck);
some(intList, localIntCheck);
some(fooList, [] (const Foo &a) { return a.check(); });
some(fooList, &fooCheck);
some(fooList, localFooCheck);
some(fooList, &Foo::check);
some(fooPtrList, [] (const Foo *a) { return a->check(); });
some(fooPtrList, &fooPtrCheck);
some(fooPtrList, localFooPtrCheck);
some(fooPtrList, &Foo::check);
some(derivedFooList, [] (const Foo &a) { return a.check(); });
some(derivedFooList, &fooCheck);
some(derivedFooList, localFooCheck);
some(derivedFooList, &Foo::check);
some(derivedFooPtrList, [] (const Foo *a) { return a->check(); });
some(derivedFooPtrList, &fooPtrCheck);
some(derivedFooPtrList, localFooPtrCheck);
some(derivedFooPtrList, &Foo::check);
return 0;
}
Note that if the value type of the collection is an object or object pointer, I want to be able to pass a pointer to a member function as the second argument to some. And that's where things get hairy.
My first attempt was to implement it like this:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const &t){ return (t.*func)(); });
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U *, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const *t){ return (t->*func)(); });
}
...but it doesn't work if the collection is not an STL collection, or at least one that takes two template arguments. In my example, using DerivedFooList or DerivedFooPtrList won't work.
My second attempt looked like this:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(const T &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
That works with DerivedFooList now, but doesn't work with std::list<Foo *> or DerivedFooPtrList.
My third attempt was this:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(typename std::enable_if<std::is_class<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
template <class T, class U>
bool some(typename std::enable_if<std::is_pointer<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const *t) { return (t->*func)(); });
}
Ignoring for the time being that this would only work with collections that have a member named value_type, it still doesn't allow my above example to compile. I think (but am not 100% sure) the reason is that it can't deduce T for the second two versions of some for the cases where I want it to be used.
I've tried very hard to see if there's a way to get what I want out of C++11, and I suspect that there is, but I can't figure it out. Is what I want possible, and if so, how do I do it?
template<class R, class F>
bool some( R const& r, F&& f ) {
for(auto&& x:r)
if (std::ref(f)(decltype(x)(x)))
return true;
return false;
}
std::ref overloads () to do the INVOKE concept, which in C++17 can be accessed directly via std::invoke. Your requirements seem to line up with the INVOKE concept.
decltype(x)(x) is equivalent to a std::forward expression if x is a deduced auto&& variable. Read it as "treat x as if it was the type it was declared as". Note that if x is an auto value, it copies, unlike forward.
INVOKE( pmf, ptr ) and INVOKE( pmf, ref ) both work. So no need to do fancy stuff in the overload.
What again is the quick way to iterate over a vector of custom objects but access only a single member in order to apply general STL-algorithms?
struct Foo
{
std::string a;
double b = 1.0;
};
int main()
{
std::vector<Foo> fooVector(20);
// iterate over all members b -- as if we were iterating over a std::vector<double>
std::discrete_distribution<int> dist(/*??*/, /*??*/);
}
With "quick" I mean
no custom iterator -- or only a very lightweight one (--a few lines of code, no boost iterator_facade, etc.),
no modification of the dereferencing operator (--not that quick).
The constructor of std::discrete_distribution<...> doesn't support any explicit way to project values (like a function object optionally applied to transform the result of *it before being used). As a result I think there are three basic approaches:
Use an intermediate std::vector<double> to obtain a range whose iterators yield doubles:
std::vector<double> tmp; // reserve() as desired
std::transform(fooVector.begin(), fooVector.end(),
std::back_inserter(tmp),
[](Foo const& f){ return f.b; });
std::discrete_distribution<int> d(tmp.begin(), tmp.end());
It may viable to use a conversion operator on Foo to convert into a double:
class Foo {
// ...
operator double() const { return this->b; }
};
// ...
std::discrete_distribution<int> d(fooVector.begin(), fooVector.end());
Create a wrapper for the iterator and use that. It doesn't need anything fancy but putting together a simple input iterators is still comparatively involved:
template <typename InIt>
class project_iterator {
InIt it;
public:
explicit project_iterator(InIt it): it(it) {}
double operator*() const { return *this->it; }
project_iterator& operator++() { ++this->it; return *this; }
project_iterator operator++(int) {
project_iterator rc(*this);
this->operator++();
return *this;
}
bool operator==(project_iterator const& other) const {
return this->it == other.it;
}
bool operator!=(project_iterator const& other) const {
return !(*this == other);
}
};
template <typename It>
project_iterator<It> project(It it) {
return project_iterator<It>(it);
}
namespace std {
template <typename It>
class iterator_traits<project_iterator<It> {
public:
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef double value_type;
typedef double& reference;
typedef double* pointer;
typedef std::input_iterator_tag iterator_category;
}
}
// ...
std::discrete_distribution<int> d(project(fooVector.begin()), project(fooVector.end());
There are, obviously, variation on these approaches but I don't think there is anything else which can be done cleverly. What is missing is essentially a general approach to have projections with sequences (I'm normally referring to them as property maps).
Here is the solution mentioned in my comment:
struct LightIterator : public std::vector<Foo>::iterator
{
LightIterator(std::vector<Foo>::iterator it) : std::vector<Foo>::iterator(it) {}
double& operator*() { return std::vector<Foo>::iterator::operator*().b; }
};
Which you can use like this:
Run It Online
std::accumulate(LightIterator{fooVector.begin()},
LightIterator{fooVector.end()},
0.0);
EDIT: #TartanLlama is right about the issue related to the actual type of std::vector<Foo>::iterator.
As an attempt to have a more generic solution, I suggest that you define a wrapper iterator class for when std::vector<Foo>::iterator is a raw pointer. Something like:
(notice that I'm now allowing arbitrary attributes to be selected. More on that later)
template <
typename PointerType,
typename ItemType,
typename AttributeType
>
struct LightIterator_FromPointer : public std::iterator<std::input_iterator_tag,
std::remove_pointer_t<PointerType>>
{
PointerType it;
AttributeType ItemType::* pointerToAttribute;
LightIterator_FromPointer(PointerType it_, AttributeType ItemType::* pointerToAttribute_)
: it(it_)
, pointerToAttribute(pointerToAttribute_)
{}
AttributeType& operator*() { return it->*pointerToAttribute; }
AttributeType* operator->() { return it; }
// input iterator boilerplate: http://en.cppreference.com/w/cpp/concept/InputIterator
using this_t = LightIterator_FromPointer<PointerType, ItemType, AttributeType>; // less typing...
LightIterator_FromPointer(const this_t& other) : it(other.it) {}
bool operator!=(const this_t& other) const { return it != other.it; }
this_t& operator++() { ++it; return *this; }
this_t operator++(const int) { return {it++}; }
};
While still keeping the original "minimal" light iterator for when std::vector<Foo>::iterator is actually a class:
template <
typename IteratorType,
typename ItemType,
typename AttributeType
>
struct LightIterator_FromClass : public IteratorType
{
AttributeType ItemType::* pointerToAttribute;
LightIterator_FromClass(IteratorType it_, AttributeType ItemType::* pointerToAttribute_)
: IteratorType(it_)
, pointerToAttribute(pointerToAttribute_)
{}
AttributeType& operator*() { return IteratorType::operator*().*pointerToAttribute; }
};
Finally, in order to abstract the details of the light iterator type that should be used on the call site, you can define a make_iterator() function that takes care of everything:
template <
typename IteratorType,
typename ItemType,
typename AttributeType
>
typename std::conditional<std::is_pointer<IteratorType>::value,
LightIterator_FromPointer<IteratorType, ItemType, AttributeType>,
LightIterator_FromClass<IteratorType, ItemType, AttributeType>
>::type
make_iterator(IteratorType it, AttributeType ItemType::* pointerToAttribute)
{
return typename std::conditional<std::is_pointer<IteratorType>::value,
LightIterator_FromPointer<IteratorType, ItemType, AttributeType>,
LightIterator_FromClass<IteratorType, ItemType, AttributeType>
>::type(it, pointerToAttribute);
}
The result is a simple calling syntax which (bonus) allows for selecting any attribute, not only Foo::b.
Run It Online
// light iterator from an actual iterator "class"
{
std::vector<Foo> fooVector(20);
double acc = std::accumulate(make_iterator(fooVector.begin(), &Foo::b),
make_iterator(fooVector.end(), &Foo::b),
0.0);
cout << acc << endl;
}
// light iterator from a "pointer" iterator
{
std::array<Foo, 20> fooVector;
double acc = std::accumulate(make_iterator(fooVector.begin(), &Foo::b),
make_iterator(fooVector.end(), &Foo::b),
0.0);
cout << acc << endl;
}
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
}