I have a vector v1, and a boolean vector v2 of the same size. I want to delete from v1 all values such that the parallel element of v2 is false:
vector<int> v3; // assume v1 is vector<int>
for (size_t i=0; i<v1.size(); i++)
if (v2[i])
v3.push_back(v1[i]);
v1=v3;
Is there a better way to do it?
in C++03
in C++11
size_t last = 0;
for (size_t i = 0; i < v1.size(); i++) {
if (v2[i]) {
v1[last++] = v1[i];
}
}
v1.erase(v1.begin() + last, v1.end());
Same as yours essentially, except it works in-place, not requiring additional storage. This is basically a reimplementation of std::remove_if (which would be difficult to use directly, because the function object it uses is given a value, not an index or iterator into the container).
In C++11 you can use std::remove_if and std::erase with a lambda, which is the "erase-remove-idiom":
size_t idx = 0;
v1.erase(std::remove_if(v1.begin(),
v1.end(),
[&idx, &v2](int val){return !v2[idx++];}),
v1.end())
And here's a link to it functioning as intended: cpp.sh/57jpc
As the comments point out however, there's a bit of discussion about the safety of doing it this way; the underlying assumption here is that std::remove_if will apply the predicate to the elements of v1 in order. However, the language in the doc doesn't explicitly guarantee this. It simply states:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. Relative order of the elements that remain is preserved and the physical size of the container is unchanged. Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition). A call to remove is typically followed by a call to a container's erase method, which erases the unspecified values and reduces the physical size of the container to match its new logical size.
Now, it would be difficult with only a forward iterator to a std::vector to both guarantee stability for results and not apply the predicate in-order. But it's certainly possible to do so.
A remove_if-based alternative is:
v1.erase(std::remove_if(v1.begin(), v1.end(),
[&v1, &v2](const int &x){ return !v2[&x - &v1[0]]; }),
v1.end());
Also consider that if you only need a view on v1 in which some elements are skipped, you can avoid to modify v1 and use something like boost::filter_iterator.
I hear you like lambdas.
auto with_index_into = [](auto&v){
return [&](auto&& f){
return [&,f=decltype(f)(f)](auto& e){
return f( std::addressof(e)-v.data(), e );
};
};
};
This may be useful. It takes a .data() suporting container, then returns a lambda of type ((Index,E&)->X)->(E&->X) -- the returned lambda converts an indexed element visitor to an element visitor. Sort of lambda judo.
template<class C, class Test>
auto erase_if( C& c, Test&& test) {
using std::begin; using std::end;
auto it=std::remove_if(begin(c),end(c),test);
if (it==end(c)) return false;
c.erase(it, end(c));
return true;
}
because I hate the remove erase idiom in client code.
Now the code is pretty:
erase_if( v1, with_index_into(v1)(
[](std::size_t i, auto&e){
return !v2[i];
}
));
The restriction on moves in remove/erase should mean it invokes the lambda on the element in its original position.
We can do this with more elemental steps. It gets complicated in the middle...
First, tiny named operator library:
namespace named_operator {
template<class D>struct make_operator{};
enum class lhs_token {
star = '*',
non_char_tokens_start = (unsigned char)-1,
arrow_star,
};
template<class T, lhs_token, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, lhs_token::star, Op>
operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op>
half_apply<Lhs, lhs_token::arrow_star, Op>
operator->*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, lhs_token::star, Op>&& lhs, Rhs&& rhs )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, lhs_token::arrow_star, Op>&& lhs, Rhs&& rhs )
{
return named_next( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
Now we define then:
namespace lambda_then {
struct then_t:named_operator::make_operator<then_t> {} then;
template<class Lhs, class Rhs>
auto named_next( Lhs&& lhs, then_t, Rhs&& rhs ) {
return
[lhs=std::forward<Lhs>(lhs), rhs=std::forward<Rhs>(rhs)]
(auto&&...args)->decltype(auto)
{
return rhs( lhs( decltype(args)(args)... ) );
};
}
}
using lambda_then::then;
which defines a token then such that lambda1 ->*then* lambda2 returns a function object that takes its arguments, passes it to lambda1, then passes the return value to lambda2.
Next we define to_index(container):
template<class C>
auto index_in( C& c ) {
return [&](auto& e){
return std::addressof(e)-c.data();
};
}
we also keep the above erase_if.
This results in:
erase_if( v1,
index_in(v1)
->*then*
[&](auto i){
return !v2[i];
}
);
solving your problem (live example).
I actually quite like the way you did it but I would make a couple of changes in limiting the scope the temporary vector is used and I would use std::vector::swap to avoid a copy at he end. If you have C++11 you could use std::move instead of std::vector::swap:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> iv = {0, 1, 2, 3, 4, 5, 6};
std::vector<bool> bv = {true, true, false, true, false, false, true};
// start a new scope to limit
// the lifespan of the temporary vector
{
std::vector<int> v;
// reserve space for performance gains
// if you don't mind an over-allocated return
// v.reserve(iv);
for(std::size_t i = 0; i < iv.size(); ++i)
if(bv[i])
v.push_back(iv[i]);
iv.swap(v); // faster than a copy
}
for(auto i: iv)
std::cout << i << ' ';
std::cout << '\n';
}
Different version that erases elements in place but does not require as many moves as Igor's algo requires and in case of small amount of elements to be erased could be more efficient:
using std::swap;
size_t last = v1.size();
for (size_t i = 0; i < last;) {
if( !v2[i] ) {
--last;
swap( v2[i], v2[last] );
swap( v1[i], v1[last] );
} else
++i;
}
v1.erase(v1.begin() + last, v1.end());
but this algo is unstable.
If you use a list (or forward_list for C++11) instead of a vector, you can do this in-place without the moving/allocating/copying overhead required for vector operations. It's perfectly possible to do most storage-related things with any STL container, but appropriate choice of containers will often give significant improvements in performance.
Related
I am currently trying to use a lambda function to std::count_if the sum of two consecutive elements in an array equal to a number. A sample code is given below.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
const int Number = 3;
std::vector<int> vec = {1,1,2,4,5,6};
auto count = std::count_if( vec.begin(), vec.end(),
[&](int A, int B) -> bool
{ return A+B == Number; });
std::cout << count << '\n';
}
The output should be 1, since we have one possible case( 1 + 2 ).
However, I could not succeed. Can anybody tell me what do I miss?
Here is the error msg:
|234|error: no match for call to '(main()::<lambda(int, int)>) (int&)'|
Problem is that std::count_if uses unary predicate. What compiler tells you: "You gave me a lambda with 2 arguments, I expected lambda with one argument".
I believe what you are looking for is std::adjacent_find. It compares every two adjacent elements of a container (possibly using a binary predicate).
Another possible option is to use std::inner_product. First I'd write a little helper function:
#include <numeric>
#include <functional>
#include <iterator>
template <typename ForwardIterator, typename BinaryPredicate>
auto count_pairs_if(ForwardIterator first, ForwardIterator last,
BinaryPredicate pred)
{
const auto n = std::distance(first, last);
if (n < 2) return std::size_t {0};
return std::inner_product(first, std::next(first, n - 1), std::next(first),
std::size_t {0}, std::plus<> {}, pred);
}
template <typename Range, typename BinaryPredicate>
auto count_pairs_if(const Range& values, BinaryPredicate pred)
{
return count_pairs_if(std::cbegin(values), std::cend(values), pred);
}
Then you can use it like:
auto count = count_pairs_if(vec, [=] (auto lhs, auto rhs) { return lhs + rhs == Number; });
Here's a demo.
As #Yksisarvinen explained, the std::count_if is designed for the unary predicate. Therefore the compiler can not accept the lambda, I passed.
After a while, I have found another solution to this problem. If I provide a templated function, which takes
iterators(i.e. start and end) of the container (on which I need to do the adjacent element check), and
the binary predicate, which will be used for checking adjacent relationship
that could be a more natural solution, like any other standard algorithm. (See a live demo online)
template <typename Iterator, typename BinaryPred = std::equal_to<>>
constexpr std::size_t count_adjacent_if(
Iterator beginIter,
const Iterator endIter,
const BinaryPred pred = {})
{
if (beginIter == endIter) return 0; // nothing to do!
std::size_t count{};
for (Iterator nextIter{ beginIter }; ++nextIter != endIter; beginIter = nextIter)
if (pred(*beginIter, *nextIter))
++count;
return count;
}
and can be called like:
const auto count = ::count_adjacent_if(
vec.cbegin(), vec.cend(), [number](const int lhs, const int rhs) { return lhs + rhs == number; }
);
Or like #bipil mentioned in the comments, let the predicate remember the previous element. Which is less recommended, since it is a non-generic solution and needs the non-empty container. (See a live demo online)
int lhs = vec[0];
const auto count = std::count_if(vec.cbegin() + 1, vec.cend(),
[&](const int rhs) {
const bool condition = (lhs + rhs == number); // check for the condition
lhs = rhs; // change the lhs = rhs (i.e. current element = next element)
return condition; // return the condition
});
I have an adapter, whose goal is to provide forward iterator for pair values pair<FeatureVector, Label>. However in my internal representation I store data as vector<pair<vector<strings>, Label>>.
So during iterations, I need to flatten it and convert every single string, which is short sentence like "oil drops massively today", to FeatureVector
In raw variant I have something like:
{
{"Oil drops massively","OPEC surge oil produciton","Brent price goes up" -> "OIL_LABEL"},
{"France consume more vine", "vine production in Italy drops" -> "VINE_LABEL"}
}
and I need to convert it to:
{
vectorize("Oil drops massively") -> "OIL_LABEL",
vectorize("OPEC surge oil produciton") -> "OIL_LABEL", ... ,
vectorize("vine production in Italy drops") -> "VINE_LABEL"
}
vectorize() -> it's a conversion from sentence to sparse vector like this "Oil drops on NYSE" -> {0,1,0..0,1,0..0,1}
The simpliest way will be create new vector and initialize it with all data and than use it's iterators, but this is pretty resource havy operation, so ideally I want this kind of conversion to be done over each iteration. What is the most elegant way for such kind of conversion?
This is a simplified version of data structure for storing text corpus. Iterators later need to be used in classifier initialization, which require 2 iterators: begin and end which is logically similar to the same as in vector.
A simple range type:
template<class It>
struct range_t {
It b{},e{};
It begin() const {return b;}
It end() const {return e;}
bool empty() const {return begin()==end();}
friend bool operator==(range_t lhs, range_t rhs){
if (lhs.empty() && rhs.empty()) return true;
return lhs.begin() == rhs.begin() && lhs.end() == rhs.end();
}
friend bool operator!=(range_t lhs, range_t rhs){
return !(lhs==rhs);
}
range_t without_front( std::size_t N = 1 ) const {
return { std::next(begin(), N), end() };
}
range_t without_back( std::size_t N = 1 ) const {
return { begin(), std::prev(end(),N) };
}
decltype(auto) front() const {
return *begin();
}
decltype(auto) back() const {
return *std::prev(end());
}
};
template<class It>
range_t<It> range( It b, It e ) {
return {b,e};
}
Here is a non-compliant pseudo-iterator that does the cross product of two ranes:
template<class ItA, class ItB>
struct cross_iterator_t {
range_t<ItA> cur_a;
range_t<ItB> orig_b;
range_t<ItB> cur_b;
cross_iterator_t( range_t<ItA> a, range_t<ItB> b ):
cur_a(a), orig_b(b), cur_b(b)
{}
bool empty() const { return cur_a.empty() || cur_b.empty(); }
void operator++(){
cur_b = cur_b.without_front();
if (cur_b.empty()) {
cur_a = cur_a.without_front();
if (cur_a.empty()) return;
cur_b = orig_b;
}
}
auto operator*()const {
return std::make_pair( cur_a.front(), cur_b.front() );
}
friend bool operator==( cross_iterator_t lhs, cross_iterator_t rhs ) {
if (lhs.empty() && rhs.empty()) return true;
auto mytie=[](auto&& self){
return std::tie(self.cur_a, self.cur_b);
};
return mytie(lhs)==mytie(rhs);
}
friend bool operator!=( cross_iterator_t lhs, cross_iterator_t rhs ) {
return !(lhs==rhs);
}
};
template<class Lhs, class Rhs>
auto cross_iterator( range_t<Lhs> a, range_t<Rhs> b )
-> cross_iterator_t<Lhs, Rhs>
{
return {a,b};
}
From this you can take std::vector<A>, B and do:
template<class A, class B>
auto cross_one_element( A& range_a, B& b_element ) {
auto a = range( std::begin(range_a), std::end(range_a) );
auto b = range( &b_element, (&b_element) +1 );
auto s = cross_iterator(a, b);
decltype(s) f{};
return cross_iterator(s, f);
}
So that solves one of your problems. The above needs to be fixed to support true input iterator featurs, not just the above pseudo-iterator that works with for(:).
Then you have to write code that takes a vector of X and transorms it into a range of f(X) for some function f.
Then you have to write code that takes a range of ranges, and flattens it into a range.
Each of these steps is no harder than above.
There are libraries that do this for you. boost has some, Rangesv3 has some, as do a pile of other range-manipulation libraries.
Boost even lets you write an iterator by specifying what to do on * and on next and on ==. Getting what to do when one of your sub-vectors is empty remains tricky, so using more generic algorithms in this case is probably wise.
The code above is not tested, and is C++14. C++11 versions are merely more verbose.
Given a list of objects, what is the cleanest way to create a functor object to act as a comparator, such that the comparator respects the ordering of the objects in the list. It is guaranteed that the objects in the list are unique, and the list contains the entire space of possible objects.
For example, suppose we have:
const std::vector<std::string> ordering {"dog", "cat", "mouse", "elephant"};
Now we want a function to act as a comparator, say for a map:
using Comparator = std::function<bool(const std::string&, const std::string&>;
using MyMap = std::map<std::string, int, Comparator>;
I have a solution, but it's not what I'd call pretty:
const auto cmp = [&ordering] (const auto& lhs, const auto& rhs)
{
const std::array<std::reference_wrapper<const std::decay_t<decltype(lhs)>, 2> values {lhs, rhs};
return *std::find_first_of(std::cbegin(ordering), std::cend(ordering),
std::cbegin(values), std::cend(values),
[] (const auto& lhs, const auto& rhs) {
return lhs == rhs.get();
}) == lhs;
};
Is there something a little less verbose?
You can use:
const std::vector<std::string> ordering {"dog", "cat", "mouse", "elephant"};
struct cmp
{
bool operator()(const std::string& lhs, const std::string& rhs)
{
return (std::find(ordering.begin(), ordering.end(), lhs) <
std::find(ordering.begin(), ordering.end(), rhs));
}
};
using MyMap = std::map<std::string, int, cmp>;
See it working at http://ideone.com/JzTNwt.
Just skip the algorithms and write a for-loop:
auto cmp = [&ordering](auto const& lhs, auto const& rhs) {
for (auto const& elem : ordering) {
// check rhs first in case the two are equal
if (elem == rhs) {
return false;
}
else if (elem == lhs) {
return true;
}
}
return false;
};
It might technically be longer than your solution, but I find it way easier to read.
Alternatively, depending on the size of the ordering, could throw both into a map:
std::unordered_map<std::string, int> as_map(std::vector<std::string> const& ordering)
{
std::unordered_map<std::string, int> m;
for (auto const& elem : ordering) {
m.emplace(elem, m.size());
}
return m;
}
auto cmp = [ordering_map = as_map(ordering)](auto const& lhs, auto const& rhs){
auto left = ordering_map.find(lhs);
auto right = ordering_map.find(rhs);
return left != ordering_map.end() && right != ordering_map.end() &&
left->second < right->second;
};
KISS. Build up your solution from reusable primitives with clear semantics.
order_by takes a projection A->B and returns an ordering on A using the ordering on B. It optionally takes an ordering on B (not used here):
template<class F, class Next=std::less<>>
auto order_by(F&& f, Next&& next = {}) {
return [f=std::forward<F>(f), next=std::forward<Next>(next)]
(auto&& lhs, auto&& rhs)->bool
{
return next(f(lhs), f(rhs));
};
}
index_in takes a container c and returns a function that takes an element, and determines its index in c:
template<class C>
auto index_in( C&& c ) {
return [c=std::forward<C>(c)](auto&& x){
using std::begin; using std::end;
return std::find( begin(c), end(c), x ) - begin(c);
};
}
template<class T>
auto index_in( std::initializer_list<T> il ) {
return [il](auto&& x){
using std::begin; using std::end;
return std::find( begin(il), end(il), x ) - begin(il);
};
}
We then compose them:
auto cmp = order_by( index_in(std::move(ordering) ) );
Each component can be independently tested and validated, and the composition "obviously" works. We can also rewrite index_in to use a faster lookup than linear, say a map from key to index, and we'd have two implementations that can unit test against each other.
I find order_by very often useful. index_in I've never had to use before.
This trick makes constructing the resulting map on one line, instead of storing cmp, practical, as the final description is short and clear.
template<class T>
using Comparator = std::function<bool(T const&, T const&>;
using MyMap = std::map<std::string, int, Comparator<std::string>>;
MyMap m = order_by( index_in({"dog", "cat", "mouse", "elephant"}) );
is also really pretty looking.
Here is a second approach.
We can move some of the work outside of the lambda.
template<class T0, class...Ts>
std::array< std::reference_wrapper<T0>, sizeof...(Ts)+1 >
make_ref_array( T0& t0, Ts&... ts ) {
return {std::ref(t0), std::ref(ts)...};
}
Then we can write the lambda from first principles instead of algorithms:
Comparator cmp = [&ordering] (const auto& lhs, const auto& rhs)
{
if (lhs==rhs) return false; // x is never less than x.
for (auto&& e:ordering)
for (auto&& z:make_ref_array(lhs, rhs))
if (e==z.get())
return std::addressof(z.get())==std::addressof(lhs);
return false;
};
The resulting lambda is a bit less verbose.
If you had ranged based algorithms it might also help.
In both my solutions, all elements not in the list are greater than any element in the list, and are equal to each other.
I suggest you make the key a structure type containing the key (std::string in this case) and the index in the array.
Something like
struct Key
{
std::string str;
size_t index;
};
using MyMap = std::map<Key, int, Comparator>;
struct Comparator
{
bool operator()(const Key &a, const Key &b) const
{
return a.index < b.index;
}
};
This is basically the same as R. Sahu's answer. But since I'd already typed it up... The primary thing I'm advocating here is keeping ordering internal to cmp, presuming that you don't need it externally.
const auto cmp = [ordering = vector<string>{ "dog", "cat", "mouse", "elephant" }](const auto& lhs, const auto& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); };
Live Example
Encapsulating the ordering within cmp makes the scope that a reader has to look at when he changes ordering much smaller. (Personally I wouldn't construct cmp as an Rvalue, I'd just dump it directly into the constructor for the same reason... Though it is becoming a bit of a redonculous one-liner:
map<string, int, function<bool(const string&, const string&)>> myMap([ordering = vector<string>{ "dog", "cat", "mouse", "elephant" }](const auto& lhs, const auto& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); });
Live Example
Is there a way to construct a vector as the concatenation of 2 vectors (Other than creating a helper function?)
For example:
const vector<int> first = {13};
const vector<int> second = {42};
const vector<int> concatenation = first + second;
I know that vector doesn't have an addition operator like string, but that's the behavior that I want. Such that concatenation would contain: 13 and 42.
I know that I can initialize concatenation like this, but it prevents me from making concatenation const:
vector<int> concatenation = first;
first.insert(concatenation.end(), second.cbegin(), second.cend());
No, it's not possible if you require that
no helper function is defined, and
the resulting vector can be declared const.
template<typename T>
std::vector<T> operator+(const std::vector<T>& v1, const std::vector<T>& v2){
std::vector<T> vr(std::begin(v1), std::end(v1));
vr.insert(std::end(vr), std::begin(v2), std::end(v2));
return vr;
}
This does require a helper "function", but at least it allows you to use it as
const vector<int> concatenation = first + second;
I think you have to write a help function. I'd write it as:
std::vector<int> concatenate(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
auto result = lhs;
std::copy( rhs.begin(), rhs.end(), std::back_inserter(result) );
return result;
}
The call it as:
const auto concatenation = concatenate(first, second);
If the vectors are likely to be very large (or contain elements that are expensive to copy), then you might need to do a reserve first to save reallocations:
std::vector<int> concatenate(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
std::vector<int> result;
result.reserve( lhs.size() + rhs.size() );
std::copy( lhs.begin(), lhs.end(), std::back_inserter(result) );
std::copy( rhs.begin(), rhs.end(), std::back_inserter(result) );
return result;
}
(Personally, I would only bother if there was evidence it was a bottleneck).
class Vector : public vector<int>
{
public:
Vector operator+(const Vector& vec);
};
Vector Vector::operator+(const Vector& vec)
{
for (int i = 0; i < vec.size(); i++)
{
this->push_back(vec[i]);
}
return *this;
}
Let me preface this by saying this is a hack, and will not give an answer to how to do this using a vector. Instead we'll depend on sizeof(int) == sizeof(char32_t) and use a u32string to contain our data.
This answer makes it exceedingly clear that only primitives can be used in a basic_string, and that any primitive larger than 32-bits would require writing a custom char_traits, but for an int we can just use u32string.
The qualification for this can be validated by doing:
static_assert(sizeof(int) == sizeof(char32_t));
Once size equality has been established, and with the knowledge that things like non-const data, and emplace or emplace_back cannot be used, u32string can be used like a vector<int>, with the notable inclusion of an addition opperator:
const vector<int> first = {13};
const vector<int> second = {42};
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());
[Live Example]
I came across this question looking for the same thing, and hoping there was an easier way than the one I came up with... seems like there isn't.
So, some iterator trickery should do it if you don't mind a helper template class:
#include <vector>
#include <iostream>
template<class T>
class concat
{
public:
using value_type = typename std::vector<T>::const_iterator::value_type;
using difference_type = typename std::vector<T>::const_iterator::difference_type;
using reference = typename std::vector<T>::const_iterator::reference;
using pointer = typename std::vector<T>::const_iterator::pointer;
using iterator_category = std::forward_iterator_tag;
concat(
const std::vector<T>& first,
const std::vector<T>& last,
const typename std::vector<T>::const_iterator& iterator) :
mFirst{first},
mLast{last},
mIterator{iterator}{}
bool operator!= ( const concat& i ) const
{
return mIterator != i.mIterator;
}
concat& operator++()
{
++mIterator;
if(mIterator==mFirst.end())
{
mIterator = mLast.begin();
}
return *this;
}
reference operator*() const
{
return *mIterator;
}
private:
const std::vector<T>& mFirst;
const std::vector<T>& mLast;
typename std::vector<T>::const_iterator mIterator;
};
int main()
{
const std::vector<int> first{0,1,2,3,4};
const std::vector<int> last{5,6,7,8,9};
const std::vector<int> concatenated(
concat<int>(first,last,first.begin()),
concat<int>(first,last,last.end()));
for(auto i: concatenated)
{
std::cout << i << std::endl;
}
return 0;
}
You may have to implement operator++(int) or operator== depending on how your STL implements the InputIterator constructor, this is the minimal iterator code example I could come up with for MingW GCC.
Have Fun! :)
I need to iterate over a vector strictly in the order the elements were pushed back into it. For my particular case it's better use iterators than iterating though the for-each loop as follows:
std::vector<int> vector;
for(int i = 0; i < vector.size(); i++)
//not good, but works
My question is if it's realiably to iterate over the vector through iterator like that:
std::vector<int> v;
for(typename std::vector<int>::iterator i = v.iterator(); i != v.end(); i++)
//good, but I'm not strictly sure about the iterating order.
So, can I use iterators safely with my requirements? Is it standartized?
If you have access to C++11 you can use range-based for loops
for (auto i : v)
Otherwise you should use begin() and end()
for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i)
You can also use std::begin and std::end (these require C++11 as well)
for (std::vector<int>::iterator i = std::begin(v); i != std::end(v); ++i)
begin will return an iterator to the first element in your vector. end will return an iterator to one element past the end of your vector. So the order in which you get the elements iterating this way is both safe and defined.
if you want to use iterators, your approach is fine
for(auto it = v.begin(); it != v.end(); ++it)
the iteration order depends in fact on the container and the actual used iterator.
for a std::vector this code iterates always over the elements in their order in the vector. if you'd use v.rbegin() or v.rend() instead, the order would be reversed.
for another container the order is different, for a std::set the very same code would iterate the elements in ascending order of their sorting criterion.
This is an overly complex solution.
First, we start with an index type. It can store anything that models iterator and/or integral (basically, supports + scalar, delta to scalar, copy, destruction and equality):
template<class T,
class Category=std::random_access_iterator_tag,
class Delta=decltype(std::declval<T>()-std::declval<T>())
>
struct index:
std::iterator<Category, T, Delta, T*, T>
{
T t;
T operator*()const{ return t; }
index& operator++(){++t; return *this;}
index operator++(int){index tmp = *this; ++t; return tmp;}
index& operator--(){--t; return *this;}
index operator--(int){index tmp = *this; --t; return tmp;}
T operator[](size_t i)const{return t+i;}
friend bool operator<(index const& lhs, index const& rhs) {
return rhs.t-lhs.t>0;
}
friend bool operator>(index const& lhs, index const& rhs) {
return rhs<lhs;
}
friend bool operator<=(index const& lhs, index const& rhs) {
return !(lhs>rhs);
}
friend bool operator>=(index const& lhs, index const& rhs) {
return !(lhs<rhs);
}
friend bool operator==(index const& lhs, index const& rhs) {
return lhs.t==rhs.t;
}
friend bool operator!=(index const& lhs, index const& rhs) {
return lhs.t!=rhs.t;
}
friend Delta operator-(index const& lhs, index const& rhs) {
return lhs.t-rhs.t;
}
friend index& operator+=(index& lhs, Delta rhs) {
lhs.t+=rhs;
return lhs;
}
friend index& operator-=(index& lhs, Delta rhs) {
lhs.t-=rhs;
return lhs;
}
friend index operator+(index idx, Delta scalar) {
idx+=scalar;
return idx;
}
friend index operator+(Delta scalar, index idx) {
idx+=scalar;
return idx;
}
friend index operator-(index idx, Delta scalar) {
idx-=scalar;
return idx;
}
};
most of which isn't needed, but I wanted to be complete. Note that this claims to be a random access iterator by default, but it lies, as its reference type is not a reference. I consider the lie worthwhile.
With index we can both create an iterator-over-integrals, and an iterator-over-iterators. Here is how we create an iterator-over-iterators:
using it_category=typename std::iterator_traits<It>::iterator_category;
template<class It, class Category=it_category<It>>
index<It, Category> meta_iterator( It it ) { return {it}; }
Next, we want to be able to take some iterators, and iterate over the range. This means we want a range type:
template<class It>
struct range {
It b, e;
range(It s, It f):b(s),e(f){}
range():b(),e(){}
It begin()const{return b;}
It end()const{return e;}
bool empty()const{return begin()==end();}
template<class R>
range(R&& r):range(std::begin(r),std::end(r)){}
};
This is a trait that takes an iterable range (not only a range, but also any container) and gets the iterator type out. Note that a superior ADL-enabled one would be a good idea:
template<class R>
using iterator=decltype(std::begin(std::declval<R&>()));
Random helpers:
template<class R,class It=iterator<R>>
range<It> make_range(R&&r){ return {std::forward<R>(r)}; }
template<class It
range<It> make_range(It s, It f){return {s,f};}
Here is a useful helper that solves our problem:
template<class R>
range<meta_iterator<iterator<R>> iterators_into( R&& r ){
return {meta_iterator(std::begin(r)), meta_iterator(std::end(r))};
}
and we are done:
std::vector<int> v;
for(auto it: iterators_into(v)) {
}
returns an iterator for each element of v.
For industrial quality, you'd want to ADL-improve things. Also, dealing with rvalue storage of input ranges lets you chain range-adaptors better in for(:) loops.