Pushing values into struct - c++

Apologies for the title, I was struggling to come up with one.
I asked a question on here Here and I'm trying to advanced with it. I have a struct:
namespace Complex {
typedef struct complex_t {
double re;
double im;
} complex;
}
And I wish to push back either an array or a vector to a 1D vector of complex, as follows:
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex> vals12(10);
for(auto i=begin; (i != end); i++)
{
vals12[i].re = *i;
}
return vals12;
}
And get the following error:
no viable overloaded operator[] for type 'vector<Complex::complex>'
vals12[i].re = *i;
Now note if I do the following:
vals12[0].re = 10;
Will work, but, when using arrays it throws this error and I cannot understand why this is. My only thought is that it could be due to the fact I'm passing an array through rather than a vector. Here is the full code:
#include <iostream>
#include <vector>
#include "complex.h"
using namespace std;
//using namespace Complex;
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex> vals12(10);
for(auto i=begin; (i != end); i++)
{
vals12[i].re = *i;
}
return vals12;
}
class Value
{
public:
template <typename Fred>
Value(Fred begin, Fred end)
{
vector<Complex::complex> vec = convertToComplex(begin, end);
}
};
int main()
{
double vals[] = {10, 23, 23, 34, 354};
Value v(std::begin(vals), std::end(vals));
}
Does anyone have any ideas to where I am going wrong? I really hope someone can help me.
Update:
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex> vals12(10);
size_t index = 0;
for(auto i=begin; (i != end); i++)
{
complex c;
c.re = *i;
c.im = *i;
vals12[index].re = c.re;
vals12[index].im = c.im;
index++;
}
return vals12;
}
Error:
error: assigning to 'double *' from incompatible type 'double'; remove *
c.re = *i;

When you declare i as auto in the for initializer it takes on the type of begin which in this case is a pointer to double. You are then attempting to pass that pointer the index operator of std::vector (although indirectly via [i]).
You will need to use an additional variable to act as the index.
size_t index = 0;
for(auto i=begin; (i != end); i++)
{
vals12[index++].re = *i;
}

Other answers have explained why your code doesn't compile. You actually want a transform algorithm:
namespace Complex {
struct complex_t {
double re;
double im;
};
}
template<typename Iterator>
vector<Complex::complex_t> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex_t> vals12;
std::transform(begin, end, std::back_inserter(vals12),
[](const double& d ){ return Complex::complex_t{d,0}; });
return vals12;
}

Note that i is an Iterator. However, operator[] expects an int for the index into the vector. You have at least two solutions:
Create a counter for the index into the vector.
Create an empty vector and use push_back().

Related

Is there a way to iterate over at most N elements using range-based for loop?

Is there a nice way to iterate over at most N elements in a container using a range-based for loop and/or algorithms from the standard library (that's the whole point, I know I can just use the "old" for loop with a condition).
Basically, I'm looking for something that corresponds to this Python code:
for i in arr[:N]:
print(i)
As I personally would use either this or this answer (+1 for both), just for increasing your knowledge - there are boost adapters you can use. For your case - the sliced seems the most appropriate:
#include <boost/range/adaptor/sliced.hpp>
#include <vector>
#include <iostream>
int main(int argc, const char* argv[])
{
std::vector<int> input={1,2,3,4,5,6,7,8,9};
const int N = 4;
using boost::adaptors::sliced;
for (auto&& e: input | sliced(0, N))
std::cout << e << std::endl;
}
One important note: N is required by sliced to be not greater than distance(range) - so safer(and slower) version is as follows:
for (auto&& e: input | sliced(0, std::min(N, input.size())))
So - once again - I would use simpler, old C/C++ approach (this you wanted to avoid in your question ;)
Here is the cheapest save solution that works for all forward iterators I could come up with:
auto begin = std::begin(range);
auto end = std::end(range);
if (std::distance(begin, end) > N)
end = std::next(begin,N);
This might run through the range almost twice, but I see no other way to get the length of the range.
You can use the good old break to manually break a loop when needed. It works even with range based loop.
#include <vector>
#include <iostream>
int main() {
std::vector<int> a{2, 3, 4, 5, 6};
int cnt = 0;
int n = 3;
for (int x: a) {
if (cnt++ >= n) break;
std::cout << x << std::endl;
}
}
C++ is great since you can code your own hideous solutions and hide them under an abstraction layer
#include <vector>
#include <iostream>
//~-~-~-~-~-~-~- abstraction begins here ~-~-~-~-~-//
struct range {
range(std::vector<int>& cnt) : m_container(cnt),
m_end(cnt.end()) {}
range& till(int N) {
if (N >= m_container.size())
m_end = m_container.end();
else
m_end = m_container.begin() + N;
return *this;
}
std::vector<int>& m_container;
std::vector<int>::iterator m_end;
std::vector<int>::iterator begin() {
return m_container.begin();
}
std::vector<int>::iterator end() {
return m_end;
}
};
//~-~-~-~-~-~-~- abstraction ends here ~-~-~-~-~-//
int main() {
std::vector<int> a{11, 22, 33, 44, 55};
int n = 4;
range subRange(a);
for ( int i : subRange.till(n) ) {
std::cout << i << std::endl; // prints 11, then 22, then 33, then 44
}
}
Live Example
The above code obviously lacks some error checking and other adjustments, but I wanted to just express the idea clearly.
This works since range-based for loops produce code similar to the following
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
cfr. begin_expr and end_expr
If your container doesn't have (or might not have) RandomAccessIterator, there is still a way to skin this cat:
int cnt = 0;
for(auto it=container.begin(); it != container.end() && cnt < N ; ++it,++cnt) {
//
}
At least for me, it is very readable :-). And it has O(N) complexity regardless of container type.
This is an index iterator. Mostly boilerplate, leaving it out, because I'm lazy.
template<class T>
struct indexT
//: std::iterator< /* ... */ > // or do your own typedefs, or don't bother
{
T t = {};
indexT()=default;
indexT(T tin):t(tin){}
indexT& operator++(){ ++t; return *this; }
indexT operator++(int){ auto tmp = *this; ++t; return tmp; }
T operator*()const{return t;}
bool operator==( indexT const& o )const{ return t==o.t; }
bool operator!=( indexT const& o )const{ return t!=o.t; }
// etc if you want full functionality.
// The above is enough for a `for(:)` range-loop
};
it wraps a scalar type T, and on * returns a copy. It also works on iterators, amusingly, which is useful here, as it lets us inherit effectively from a pointer:
template<class ItA, class ItB>
struct indexing_iterator:indexT<ItA> {
ItB b;
// TODO: add the typedefs required for an iterator here
// that are going to be different than indexT<ItA>, like value_type
// and reference etc. (for simple use, not needed)
indexing_iterator(ItA a, ItB bin):ItA(a), b(bin) {}
indexT<ItA>& a() { return *this; }
indexT<ItA> const& a() const { return *this; }
decltype(auto) operator*() {
return b[**a()];
}
decltype(auto) operator->() {
return std::addressof(b[**a()]);
}
};
The indexing iterator wraps two iterators, the second of which must be random-access. It uses the first iterator to get an index, which it uses to look up a value from the second.
Next, we have is a range type. A SFINAE-improved one can be found many places. It makes iterating over a range of iterators in a for(:) loop easy:
template<class Iterator>
struct range {
Iterator b = {};
Iterator e = {};
Iterator begin() { return b; }
Iterator end() { return e; }
range(Iterator s, Iterator f):b(s),e(f) {}
range(Iterator s, size_t n):b(s), e(s+n) {}
range()=default;
decltype(auto) operator[](size_t N) { return b[N]; }
decltype(auto) operator[] (size_t N) const { return b[N]; }\
decltype(auto) front() { return *b; }
decltype(auto) back() { return *std::prev(e); }
bool empty() const { return begin()==end(); }
size_t size() const { return end()-begin(); }
};
Here are helpers to make working with ranges of indexT easy:
template<class T>
using indexT_range = range<indexT<T>>;
using index = indexT<size_t>;
using index_range = range<index>;
template<class C>
size_t size(C&&c){return c.size();}
template<class T, std::size_t N>
size_t size(T(&)[N]){return N;}
index_range indexes( size_t start, size_t finish ) {
return {index{start},index{finish}};
}
template<class C>
index_range indexes( C&& c ) {
return make_indexes( 0, size(c) );
}
index_range intersect( index_range lhs, index_range rhs ) {
if (lhs.b.t > rhs.e.t || rhs.b.t > lhs.b.t) return {};
return {index{(std::max)(lhs.b.t, rhs.b.t)}, index{(std::min)(lhs.e.t, rhs.e.t)}};
}
ok, almost there.
index_filter_it takes a range of indexes and a random access iterator, and makes a range of indexed iterators into that random access iterator's data:
template<class R, class It>
auto index_filter_it( R&& r, It it ) {
using std::begin; using std::end;
using ItA = decltype( begin(r) );
using R = range<indexing_iterator<ItA, It>>;
return R{{begin(r),it}, {end(r),it}};
}
index_filter takes an index_range and a random access container, intersects their indexes, then calls index_filter_it:
template<class C>
auto index_filter( index_range r, C& c ) {
r = intersect( r, indexes(c) );
using std::begin;
return index_filter_it( r, begin(c) );
}
and now we have:
for (auto&& i : index_filter( indexes(0,6), arr )) {
}
and viola, we have a large musical instrument.
live example
Fancier filters are possible.
size_t filter[] = {1,3,0,18,22,2,4};
using std::begin;
for (auto&& i : index_filter_it( filter, begin(arr) ) )
will visit 1, 3, 0, 18, 22, 2, 4 in arr. It does not, however, bounds-check, unless arr.begin()[] bounds-checks.
There are probably errors in the above code, and you should probably just use boost.
If you implement - and [] on indexT, you can even daisy chain these ranges.
Since C++20 you can add the range adaptor std::views::take from the Ranges library to your range-based for loop. This way you can implement a similar solution to the one in PiotrNycz's answer, but without using Boost:
int main() {
std::vector<int> v {1, 2, 3, 4, 5, 6, 7, 8, 9};
const int N = 4;
for (int i : v | std::views::take(N))
std::cout << i << std::endl;
return 0;
}
The nice thing about this solution is that N may be larger than the size of the vector. This means, for the example above, it is safe to use N = 13; the complete vector will then be printed.
Code on Wandbox
This solution doesn't go past end(), has O(N) complexity for std::list (doesn't use std::distance) works with std::for_each, and only requires ForwardIterator:
std::vector<int> vect = {1,2,3,4,5,6,7,8};
auto stop_iter = vect.begin();
const size_t stop_count = 5;
if(stop_count <= vect.size())
{
std::advance(stop_iter, n)
}
else
{
stop_iter = vect.end();
}
std::for_each(vect.vegin(), stop_iter, [](auto val){ /* do stuff */ });
The only thing it doesn't do is work with InputIterator such as std::istream_iterator - you'll have to use external counter for that.
First we write an iterator which stops at a given index:
template<class I>
class at_most_iterator
: public boost::iterator_facade<at_most_iterator<I>,
typename I::value_type,
boost::forward_traversal_tag>
{
private:
I it_;
int index_;
public:
at_most_iterator(I it, int index) : it_(it), index_(index) {}
at_most_iterator() {}
private:
friend class boost::iterator_core_access;
void increment()
{
++it_;
++index_;
}
bool equal(at_most_iterator const& other) const
{
return this->index_ == other.index_ || this->it_ == other.it_;
}
typename std::iterator_traits<I>::reference dereference() const
{
return *it_;
}
};
We can now write an algorithme for making a rage of this iterator from a given range:
template<class X>
boost::iterator_range<
at_most_iterator<typename X::iterator>>
at_most(int i, X& xs)
{
typedef typename X::iterator iterator;
return std::make_pair(
at_most_iterator<iterator>(xs.begin(), 0),
at_most_iterator<iterator>(xs.end(), i)
);
}
Usage:
int main(int argc, char** argv)
{
std::vector<int> xs = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int x : at_most(5, xs))
std::cout << x << "\n";
return 0;
}

How can I efficiently insert a series of items into the middle std::deque with C++03?

I'm using C++03 to insert a sequence of integers into a std::deque<int>. The only way I see to insert one time into a deque is using either the overloading that takes a position, count, and value or using a position, beginning input iterator, and ending input iterator. If I could use the later, I would do this:
#include <deque>
#include <boost/iterator/counting_iterator.hpp>
void
insertRecent(const int begin,
const int end, // Assumes end >= begin
std::deque<int> &_recent,
std::deque<int>::iterator insertionPoint)
{
_recent.insert(insertionPoint,
boost::counting_iterator<int>(begin),
boost::counting_iterator<int>(end));
}
However, the boost::counting_iterator is not available on all the platforms I am using and further on some platforms the compiler runs into a bug with it. Therefore, I'm trying to do this with the first overloading as follows, but wonder if there is a more efficient way to do this:
#include <deque>
void
insertRecent(const int begin,
const int end, // Assumes end >= begin
std::deque<int> &_recent,
std::deque<int>::iterator insertionPoint)
{
if (begin != end) {
int offset = begin;
const size_type count = static_cast<size_type>(end - begin);
const size_type insertEndDistance = _recent.end() - insertionPoint;
// Make space for all the items being inserted.
_recent.insert(insertionPoint, count, begin);
// Start off at the iterator position of the first item just inserted.
// In C++11 we can just use the return value from deque::insert().
std::deque<int>::iterator itr = _recent.end() - (count + insertEndDistance);
for (; ++offset != end; ) {
*++itr = offset;
}
}
}
I believe this approach is linear on the (end - begin) range and linear on the distance from (_recent.end() - insertionPoint). Am I correct in thinking this is as good as I can do here?
You can make your own counting iterator:
class my_int_iterator {
int v_;
public:
my_int_iterator (int v = 0) : v_(v) {}
int operator * () const { return v_; }
my_int_iterator & operator ++ () { ++v_; return *this; }
bool operator != (my_int_iterator mii) const { return v_ != mii.v_; }
typedef std::input_iterator_tag iterator_category;
typedef int value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
};
void
insertRecent(const int begin,
const int end, // Assumes end >= begin
std::deque<int> &_recent,
std::deque<int>::iterator insertionPoint)
{
_recent.insert(insertionPoint,
my_int_iterator(begin),
my_int_iterator(end));
}

Get index in C++11 foreach loop

Is there a convenient way to get the index of the current container entry in a C++11 foreach loop, like enumerate in python:
for idx, obj in enumerate(container):
pass
I could imagine an iterator that can also return the index or similar.
Of course I could have a counter, but often iterators don't give guarantees of the order they iterate over a container.
A good implementation of the feature you are requested can be found here:
https://github.com/ignatz/pythonic
The idea behind is, that you build a wrapper struct with a custom iterator that does the counting. Below is a very minimal exemplary implementation to illustrate the idea:
// Distributed under the terms of the GPLv2 or newer
#include <iostream>
#include <vector>
#include <tuple>
// Wrapper class
template <typename T>
class enumerate_impl
{
public:
// The return value of the operator* of the iterator, this
// is what you will get inside of the for loop
struct item
{
size_t index;
typename T::value_type & item;
};
typedef item value_type;
// Custom iterator with minimal interface
struct iterator
{
iterator(typename T::iterator _it, size_t counter=0) :
it(_it), counter(counter)
{}
iterator operator++()
{
return iterator(++it, ++counter);
}
bool operator!=(iterator other)
{
return it != other.it;
}
typename T::iterator::value_type item()
{
return *it;
}
value_type operator*()
{
return value_type{counter, *it};
}
size_t index()
{
return counter;
}
private:
typename T::iterator it;
size_t counter;
};
enumerate_impl(T & t) : container(t) {}
iterator begin()
{
return iterator(container.begin());
}
iterator end()
{
return iterator(container.end());
}
private:
T & container;
};
// A templated free function allows you to create the wrapper class
// conveniently
template <typename T>
enumerate_impl<T> enumerate(T & t)
{
return enumerate_impl<T>(t);
}
int main()
{
std::vector<int> data = {523, 1, 3};
for (auto x : enumerate(data))
{
std::cout << x.index << ": " << x.item << std::endl;
}
}
What about a simple solution like:
int counter=0;
for (auto &val: container)
{
makeStuff(val, counter);
counter++;
}
You could make a bit more "difficult" to add code after the counter by adding a scope:
int counter=0;
for (auto &val: container)
{{
makeStuff(val, counter);
}counter++;}
As #graham.reeds pointed, normal for loop is also a solution, that could be as fast:
int counter=0;
for (auto it=container.begin(); it!=container.end(); ++it, ++counter)
{
makeStuff(val, counter);
}
And finally, a alternative way using algorithm:
int counter = 0;
std::for_each(container.begin(), container.end(), [&counter](int &val){
makeStuff(val, counter++);
});
Note: the order between range loop and normal loop is guaranteed by the standard 6.5.4. Meaning the counter is able to be coherent with the position in the container.
If you have access to Boost its range adaptors can be used like this:
#include <boost/range/adaptor/indexed.hpp>
using namespace boost::adaptors;
for (auto const& elem : container | indexed(0))
{
std::cout << elem.index() << " - " << elem.value() << '\n';
}
Source (where there are also other examples)
C++17 and structured bindings makes this look OK - certainly better than some ugly mutable lambda with a local [i = 0](Element&) mutable or whatever I've done before admitting that probably not everything should be shoehorned into for_each() et al. - and than other solutions that require a counter with scope outside the for loop.
for (auto [it, end, i] = std::tuple{container.cbegin(), container.cend(), 0};
it != end; ++it, ++i)
{
// something that needs both `it` and `i`ndex
}
You could make this generic, if you use this pattern often enough:
template <typename Container>
auto
its_and_idx(Container&& container)
{
using std::begin, std::end;
return std::tuple{begin(container), end(container), 0};
}
// ...
for (auto [it, end, i] = its_and_idx(foo); it != end; ++it, ++i)
{
// something
}
C++ Standard proposal P2164 proposes to add views::enumerate, which would provide a view of a range giving both reference-to-element and index-of-element to a user iterating it.
We propose a view enumerate whose value type is a struct with 2 members index and value representing respectively the position and value of the elements in the adapted range.
[ . . .]
This feature exists in some form in Python, Rust, Go (backed into the language), and in many C++ libraries: ranges-v3, folly, boost::ranges (indexed).
The existence of this feature or lack thereof is the subject of recurring stackoverflow questions.
Hey, look! We're famous.
If you need the index then a traditional for works perfectly well.
for (int idx=0; idx<num; ++idx)
{
// do stuff
}

Copy multidimensional array to vector and vice versa

int dArray[1600][32];
vector < vector <int> > dVector;
n= 1600; k = 32
dVector.resize(n);
for(int i = 0 ; i < n ; ++i){
dVector[i].resize(k);
}
std::copy ( dArray, dArray + tmp_c, std::back_inserter (dVector));
How do i use the std::copy ( or any other function ) to copy an multi dimensional array to a vector and vice versa?
You can't do it directly, but with an intermediate step. Depending on your requirements, something like this vector_wrapper might work for you
#include <vector>
template<typename T, int N> struct vector_wrapper {
vector_wrapper(T (&a)[N]) {
std::copy(a, a + N, std::back_inserter(v));
}
std::vector<T> v;
};
int dArray[1600][32];
std::vector<vector_wrapper<int, 32> > dVector;
int main(int argc, char **argv)
{
std::copy(dArray, dArray + 1600, std::back_inserter(dVector));
return 0;
}
You'll basically need to write your own kind of output iterator. It's a bit ugly, but something like this should do the trick:
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename ContainerOfContainer, typename Container, std::size_t n>
struct nested_back_inserter : public std::iterator<std::output_iterator_tag, void,
void, void, void>
{
std::size_t k;
std::size_t current_;
ContainerOfContainer* container_;
explicit nested_back_inserter(ContainerOfContainer& cont)
: k(0), current_(0), container_(&cont)
{ }
nested_back_inserter& operator=(typename Container::value_type value)
{
if(k == n) {
++current_;
k = 0;
}
(*container_)[current_].push_back(value);
++k;
return *this;
}
nested_back_inserter& operator*()
{
return *this;
}
nested_back_inserter& operator++()
{
return *this;
}
nested_back_inserter& operator++(int)
{
return *this;
}
};
int main()
{
int arr[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
std::vector<std::vector<int>> v;
for(unsigned i = 0; i < 3; ++i) {
std::vector<int> vi;
v.push_back(vi);
}
typedef std::vector<std::vector<int>> nested;
typedef std::vector<int> cont;
std::copy(arr[0], arr[2] + 3, nested_back_inserter<nested, cont, 3>(v));
for(auto it = v.begin(); it != v.end(); ++it) {
std::cout << "{";
for(auto it2 = it->begin(); it2 != it->end(); ++it2) {
std::cout << *it2 << ", ";
}
std::cout << "}\n";
}
return 0;
}
Note specifically the uglyness in std::copy(arr[0], arr[2] + 3, ...);.
Due to tiredness, I take no responsibility for any off-by-one errors or other oddness that could occur with this. It should give you an idea of how to implement something like this however.
You will have to write your own iterator that, upon dereference, produces a helper object that, upon assignment, copies a one-dimensional array to a vector with std::copy (and for copying to the opposite direction, another iterator that does the opposite). Basically, take a look at how back_insert_iterator is implemented, and do pretty much the same, only instead of push_back call std::copy.
Personally I think it's not worth it. I'd just use a for loop for the outer copy. You already have one, just add std::copy to its body, right after resize.
Note that if you resize your vectors beforehand, you don't need std::back_inserter as it will allocate yet more storage. Use begin instead.

Python-like loop enumeration in C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
The community reviewed whether to reopen this question 6 months ago and left it closed:
Original close reason(s) were not resolved
Possible Duplicate:
Find position of element in C++11 range-based for loop?
I have a vector and I would like to iterate it and, at the same time, have access to the indexes for each individual element (I need to pass both the element and its index to a function). I have considered the following two solutions:
std::vector<int> v = { 10, 20, 30 };
// Solution 1
for (std::vector<int>::size_type idx = 0; idx < v.size(); ++idx)
foo(v[idx], idx);
// Solution 2
for (auto it = v.begin(); it != v.end(); ++it)
foo(*it, it - v.begin());
I was wondering whether there might be a more compact solution. Something similar to Python's enumerate. This is the closest that I got using a C++11 range-loop, but having to define the index outside of the loop in a private scope definitely seems to be like a worse solution than either 1 or 2:
{
int idx = 0;
for (auto& elem : v)
foo(elem, idx++);
}
Is there any way (perhaps using Boost) to simplify the latest example in such a way that the index gets self-contained into the loop?
Here is some kind of funny solution using lazy evaluation. First, construct the generator object enumerate_object:
template<typename Iterable>
class enumerate_object
{
private:
Iterable _iter;
std::size_t _size;
decltype(std::begin(_iter)) _begin;
const decltype(std::end(_iter)) _end;
public:
enumerate_object(Iterable iter):
_iter(iter),
_size(0),
_begin(std::begin(iter)),
_end(std::end(iter))
{}
const enumerate_object& begin() const { return *this; }
const enumerate_object& end() const { return *this; }
bool operator!=(const enumerate_object&) const
{
return _begin != _end;
}
void operator++()
{
++_begin;
++_size;
}
auto operator*() const
-> std::pair<std::size_t, decltype(*_begin)>
{
return { _size, *_begin };
}
};
Then, create a wrapper function enumerate that will deduce the template arguments and return the generator:
template<typename Iterable>
auto enumerate(Iterable&& iter)
-> enumerate_object<Iterable>
{
return { std::forward<Iterable>(iter) };
}
You can now use your function that way:
int main()
{
std::vector<double> vec = { 1., 2., 3., 4., 5. };
for (auto&& a: enumerate(vec)) {
size_t index = std::get<0>(a);
double& value = std::get<1>(a);
value += index;
}
}
The implementation above is a mere toy: it should work with both const and non-const lvalue-references as well as rvalue-references, but has a real cost for the latter though, considering that it copies the whole iterable object several times. This problem could surely be solved with additional tweaks.
Since C++17, decomposition declarations even allow you to have the cool Python-like syntax to name the index and the value directly in the for initializer:
int main()
{
std::vector<double> vec = { 1., 2., 3., 4., 5. };
for (auto&& [index, value] : enumerate(vec)) {
value += index;
}
}
A C++-compliant compiler decomposes auto&& inferring index as std::size_t&& and value as double&.
As #Kos says, this is such a simple thing that I don't really see the need to simplify it further and would personally just stick to the traditional for loop with indices, except that I'd ditch std::vector<T>::size_type and simply use std::size_t:
for(std::size_t i = 0; i < v.size(); ++i)
foo(v[i], i);
I'm not too keen on solution 2. It requires (kinda hidden) random access iterators which wouldn't allow you to easily swap the container, which is one of the strong points of iterators. If you want to use iterators and make it generic (and possibly incur a performance hit when the iterators are not random access), I'd recommend using std::distance:
for(auto it(v.begin()); it != v.end(); ++it)
foo(*it, std::distance(it, v.begin());
One way is to wrap the loop in a function of your own.
#include <iostream>
#include <vector>
#include <string>
template<typename T, typename F>
void mapWithIndex(std::vector<T> vec, F fun) {
for(int i = 0; i < vec.size(); i++)
fun(vec[i], i);
}
int main() {
std::vector<std::string> vec = {"hello", "cup", "of", "tea"};
mapWithIndex(vec, [](std::string s, int i){
std::cout << i << " " << s << '\n';
} );
}