Related
Suppose we have a plain array (or other container which supports range-based loops):
const int N = 8;
int arr[N] = {0, 1, 2, 3, 4, 5, 6, 7};
Using indexes or iterators, we can loop over odd elements and increment the index by two:
for (int i = 0; i < N; i+=2)
{
std::cout << arr[i] << std::endl;
}
How can I get a similar result by using a range-based loop and avoiding explicit iterators/indexes and iteration skipping? Something like this:
for (const auto& v: odd_only(arr))
{
std::cout << v << std::endl;
}
What does a simple and elegant solution look like? Does the standard library contain something like this?
There's no support for what you request – but you might write your own even_only and odd_only implementations.
Basic idea is to wrap around the normal iterator of the container in question and do a double increment internally each time we increment once externally:
template <typename C, bool IsOdd>
class even_odd_only
{
C& c;
public:
class iterator
{
public:
// all the definitions required for iterator!
// most if not all might simply be derived from C::iterator...
// copy/move constructor/assignment as needed
// core of the wrapper: increment twice internally!
// just doing += 2 is dangerous, though, we might increment beyond
// the end iterator (undefined behaviour!)additionally, += 2 only
// is possible for random access iterators (so we limit usability)
void operator++() { ++b; if(b != e) ++b; }
// operator* and operator-> (both return *b), post-increment
// (defined in terms of pre-increment), etc...
// comparison: only needs to compare b iterators!
private:
C::iterator b;
C::iterator e; // needed for comparison to avoid incrementing beyond!
iterator(C::iterator b, C::iterator e) : b(b), e(e) { }
};
// const_iterator, too; possibly make a template of above
// and derive const and non-const iterators from?
even_odd_only(C& c) : c(c) { }
iterator begin()
{
using std::begin;
using std::end;
using std::empty;
auto b = begin(c);
// should be self-explanatory:
// skip first element in odd variant (if there is)
if constexpr(IsOdd) { if(!empty(c)) { ++b; } }
return iterator(b, end(c));
};
iterator end()
{
using std::end;
return iterator(end(c), end(c));
}
};
template <typename T>
using even_only = even_odd_base<T, false>;
template <typename T>
using odd_only = even_odd_base<T, true>;
As is, it would work even with non-random-access and even non-bidirectional iterators. But especially for RA-iterators, it's less efficient than the classic loop (due to the intermediate if in operator++).
Defining comparison iterators: always operator== and operator!=, only for random access operators you can additionally have operator[<|>|<=|>=] (→ std::enable_if).
You'll find more details about how to write an iterator here – keep in mind when you encounter, though, that std::iterator itself is deprecated now.
As for what you are currently asking; I do not believe anything exists yet. Now as for iterating over a container by some integer N we can do the following; we can write our own for_each type of function. I've written one below and it works like a gem! You may also want to look into the std::advance function as well for it can be another possible implementation. I was checking that out myself as I was writing this function. However; as for c arrays I'm not sure there is much one can do without a bunch of extra code such as class templates, wrappers, etc. Here is my function.
#include <array>
#include <vector>
#include <iterator>
template<typename Container, typename Function>
void for_each_by_n( Container&& cont, Function f, unsigned increment_by = 1) {
if ( increment_by == 0 ) return; // must check this for no op
using std::begin;
auto it = begin(cont);
using std::end;
auto end_it = end(cont);
while( it != end_it ) {
f(*it);
for ( unsigned n = 0; n < increment_by; ++n ) {
if ( it == end_it ) return;
++it;
}
}
}
int main() {
std::array<int,8> arr{ 0,1,2,3,4,5,6,7 };
std::vector<double> vec{ 1.2, 1.5, 1.9, 2.5, 3.3, 3.7, 4.2, 4.8 };
auto l = [](auto& v) { std::cout << v << ' '; };
for_each_by_n(arr, l); std::cout << '\n';
for_each_by_n(vec, l); std::cout << '\n';
for_each_by_n(arr, l, 2); std::cout << '\n';
for_each_by_n(arr, l, 4); std::cout << '\n';
for_each_by_n(vec, l, 3); std::cout << '\n';
for_each_by_n(vec, l, 5); std::cout << '\n';
for_each_by_n(arr, l, 8); std::cout << '\n';
for_each_by_n(vec, l, 8); std::cout << '\n';
// sanity check to see if it doesn't go past end.
for_each_by_n(arr, l, 9); std::cout << '\n';
for_each_by_n(vec, l, 9); std::cout << '\n';
return 0;
}
-Output-
0 1 2 3 4 5 6 7
1.2 1.5 1.9 2.5 3.3 3.7 4.2 4.8
0 2 4 6
0 4
1.2 2.5 4.2
1.2 3.7
0
1.2
0
1.2
What I like about this example above is that not only can you increment through a loop by some integer N; the above function also takes a function pointer, function object, functor, or lambda and it will perform the required action.
In your case you was trying to loop through your container by 2 for ever odd or every even index and within the loop you were printing the results. Here in my example; I'm printing the results in the form of a lambda that is being passed to this function.
However the only caveat with this particular implementation is that it will always start from index 0. You could easily expand on this by introducing another integer parameter as to an offset of where the iteration will begin; but I'll leave that up to you to do as an exercise.
For the time being we have to settle for what C++11 through C++17 has to offer. In the near future we should have many new and powerful features with the release of C++20.
There is a ready-made solution for this problem in the Range-v3. I think this can be useful if you don’t want to write your own implementation or need more flexibility (f.e. arbitrary stride)
#include <range/v3/all.hpp>
void example()
{
int data[8] = {0, 1, 2, 3, 4, 5, 6, 7};
for (auto i : ranges::view::stride(data, 2))
{
std::cout << i << std::endl;
}
}
(copied from #hlt comment)
This isn't really an answer to the question, but—for what it is worth—whenever I run into a limitation of ranged-for, I look for a standard algorithm solution. Like...
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
int main()
{
int arr[] {0, 1, 2, 3, 4, 5, 6, 7};
std::copy_if(
std::begin(arr), std::end(arr),
std::ostream_iterator<int>(std::cout, "\n"),
[is_odd_element = true](int n) mutable {
return std::exchange(is_odd_element, not is_odd_element);
});
}
I have a class named ItemType. It has two members - both double, named m_t and m_f. Two items of type ItemType are considered to be equal if these two members differ from each other within respective tolerance levels. With this logic, the comparator function is so defined as well. However, when I insert objects of this type as key into a map, only one key is produced in the map, even though at least three such keys should be present:
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <vector>
using namespace std;
class ItemKey
{
public:
ItemKey(double t, double f)
{
m_t = t;
m_f = f;
}
double m_t;
double m_f;
double m_tEpsilon = 3;
double m_fEpsilon = 0.1;
bool operator<(const ItemKey& itemKey) const
{
int s_cmp = (abs(itemKey.m_f - m_f) > m_fEpsilon);
if (s_cmp == 0)
{
return (abs(itemKey.m_t - m_t) > m_tEpsilon);
}
return s_cmp < 0;
}
};
int main()
{
// The pairs are the respective values of m_t and m_f.
vector<pair<double, double>> pairs;
// These two should belong in one bucket -> (109.9, 9.0), because m_f differs by 0.09 and m_t differs by just 1
pairs.emplace_back(109.9, 9.0);
pairs.emplace_back(110.9, 9.09);
// This one is separate from above two beause even though m_t is in range, m_f is beyong tolerance level
pairs.emplace_back(109.5, 10.0);
// Same for this as well, here both m_t and m_f are beyong tolerance of any of the two categories found above
pairs.emplace_back(119.9, 19.0);
// This one matches the second bucket - (109.5, 10.0)
pairs.emplace_back(109.9, 10.05);
// And this one too.
pairs.emplace_back(111.9, 9.87);
map<ItemKey, size_t> itemMap;
for (const auto& item: pairs)
{
ItemKey key(item.first, item.second);
auto iter = itemMap.find(key);
if (iter == itemMap.end())
{
itemMap[key] = 1;
}
else
{
itemMap[iter->first] = itemMap[iter->first] + 1;
}
}
// The map should have three keys - (109.9, 9.0) -> count 2, (109.5, 10.0) -> count 3 and (119.9, 19.0) -> count 1
cout << itemMap.size();
}
However, the map seems to have only 1 key. How do I make it work as expected?
Why isn't your version working?
You did well to create your own comparison function. To answer your question, you have an error in your operator<() function such that only returns true if m_f is outside of tolerance and m_t is within tolerance, which I'm guessing is not what you desired. Let's take a look.
int s_cmp = (abs(itemKey.m_f - m_f) > m_fEpsilon);
The above line basically is checking whether this->m_f and itemKey.m_f are within tolerance of eachother (meaning equal to each other). That is probably what was intended. Then you say
if (s_cmp == 0)
{
return (abs(itemKey.m_t - m_t) > m_tEpsilon);
}
If s_cmp is true, then it will have the value of 1, and it will have a value of 0 for false (meaning that they are not within tolerance of each other). Then you return true if the m_t value is within tolerance. Up to this point, you return true if m_f is not equal (according to tolerance) and if m_t is equal (according to tolerance). Then your last line of code
return s_cmp < 0;
will return true always since a boolean converted to an integer cannot ever be negative.
How to get it working?
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <vector>
struct ItemKey
{
double m_t;
double m_f;
static constexpr double t_eps = 3;
static constexpr double f_eps = 0.1;
ItemKey(double t, double f) : m_t(t), m_f(f) {}
bool operator<(const ItemKey& other) const
{
// Here it is assumed that f_eps and t_eps are positive
// We also ignore overflow, underflow, and NaN
// This is written for readability, and assumed the compiler will be
// able to optimize it.
auto fuzzy_less_than = [] (double a, double b, double eps) {
return a < b - eps;
};
bool f_is_less_than = fuzzy_less_than(this->m_f, other.m_f, f_eps);
bool f_is_greater_than = fuzzy_less_than(other.m_f, this->m_f, f_eps);
bool f_is_equal = !f_is_less_than && !f_is_greater_than;
bool t_is_less_than = fuzzy_less_than(this->m_t, other.m_t, t_eps);
return f_is_less_than || (f_is_equal && t_is_less_than);
}
};
int main()
{
using namespace std;
// The pairs are the respective values of m_t and m_f.
vector<pair<double, double>> pairs;
// These two should belong in one bucket
// -> (109.9, 9.0), because m_f differs by 0.09 and m_t differs by just 1
pairs.emplace_back(109.9, 9.0);
pairs.emplace_back(110.9, 9.09);
// This one is separate from above two beause even though m_t is in range,
// m_f is beyong tolerance level
pairs.emplace_back(109.5, 10.0);
// Same for this as well, here both m_t and m_f are beyong tolerance of any
// of the two categories found above
pairs.emplace_back(119.9, 19.0);
// This one matches the second bucket - (109.5, 10.0)
pairs.emplace_back(109.9, 10.05);
// And this one too.
pairs.emplace_back(111.9, 9.87);
map<ItemKey, size_t> itemMap;
for (const auto& item: pairs)
{
ItemKey key(item.first, item.second);
auto iter = itemMap.find(key);
if (iter == itemMap.end())
{
itemMap[key] = 1;
}
else
{
itemMap[iter->first] = itemMap[iter->first] + 1;
}
}
// The map should have three keys
// - (109.9, 9.0) -> count 2
// - (109.5, 10.0) -> count 3
// - (119.9, 19.0) -> count 1
cout << itemMap.size();
cout << "itemMap contents:" << endl;
for (auto& item : itemMap) {
cout << " (" << item.first << ", " << ")" << endl;
}
return 0;
}
There are a few things I changed above. I have a few suggestions also unrelated to the programming mistake:
Do not store boolean values into integer variables.
There's a reason that C++ introduced the bool type.
Write your code to be readable and in a way that the compiler
can easily optimize. You may notice I used a lambda expression
and multiple booleans. Smart compilers will inline the calls to
that lambda expression since it is only used within the local scope.
Also smart compilers can simplify boolean logic and make it
performant for me.
The m_tEpsilon and m_fEpsilon are probably not good to be
changable variables of the class. In fact, it may be bad if one
object has a different epsilon than another one. If that were the
case, which do you use when you do the < operator? For this
reason, I set them as static const variables in the class.
For constructors, it is better to initialize your variables in the
initializer list rather than in the body of the constructor. That
is unless you are doing dynamic resource allocation, then you would
want to do it in the constructor and make sure to clean it up if
you end up throwing an exception (preferrably using the RAII
pattern). I'm starting to get too far off topic :)
Even though class and struct are basically identical except for
the default protection level (class is private by default and
struct is public by default). It is convention to have it as a
struct if you want direct access to the member variables. Although,
in this case, I would probably set your class as immutable. To do
that, set the m_t and m_f as private variables and have a getter
m() and f(). It might be a bad idea to modify an ItemKey
instance in a map after it has been inserted.
Potential problems with this approach
One of the problems you have with your approach here is that it will be dependent on the order in which you add elements. Consider the following pairs to be added: (3.0, 10.0) (5.0, 10.0) (7.0, 10.0). If we add them in that order, we will get (3.0, 10.0) (7.0, 10.0), since (5.0, 10.0) was deemed to be equal to (3.0, 10.0). But what if we were to have inserted (5.0, 10.0) first, then the other two? Well then the list would only have one element, (5.0, 10.0), since bother of the others would be considered equal to this one.
Instead, I would like to suggest that you use std::multiset instead, of course this will depend on your application. Consider these tests:
void simple_test_map() {
std::map<ItemKey, size_t> counter1;
counter1[{3.0, 10.0}] += 1;
counter1[{5.0, 10.0}] += 1;
counter1[{7.0, 10.0}] += 1;
for (auto &itempair : counter1) {
std::cout << "simple_test_map()::counter1: ("
<< itempair.first.m_t << ", "
<< itempair.first.m_f << ") - "
<< itempair.second << "\n";
}
std::cout << std::endl;
std::map<ItemKey, size_t> counter2;
counter2[{5.0, 10.0}] += 1;
counter2[{3.0, 10.0}] += 1;
counter2[{7.0, 10.0}] += 1;
for (auto &itempair : counter2) {
std::cout << "simple_test_map()::counter2: ("
<< itempair.first.m_t << ", "
<< itempair.first.m_f << ") - "
<< itempair.second << "\n";
}
std::cout << std::endl;
}
This outputs:
simple_test_map()::counter1: (3, 10) - 2
simple_test_map()::counter1: (7, 10) - 1
simple_test_map()::counter2: (5, 10) - 3
And for the multiset variant:
void simple_test_multiset() {
std::multiset<ItemKey> counter1 {{3.0, 10.0}, {5.0, 10.0}, {7.0, 10.0}};
for (auto &item : counter1) {
std::cout << "simple_test_multiset()::counter1: ("
<< item.m_t << ", "
<< item.m_f << ")\n";
}
std::cout << std::endl;
std::multiset<ItemKey> counter2 {{5.0, 10.0}, {3.0, 10.0}, {7.0, 10.0}};
for (auto &item : counter2) {
std::cout << "simple_test_multiset()::counter2: ("
<< item.m_t << ", "
<< item.m_f << ")\n";
}
std::cout << std::endl;
std::cout << "simple_test_multiset()::counter2.size() = "
<< counter2.size() << std::endl;
for (auto &item : counter1) {
std::cout << "simple_test_multiset()::counter2.count({"
<< item.m_t << ", "
<< item.m_f << "}) = "
<< counter1.count(item) << std::endl;
}
std::cout << std::endl;
}
This outputs
simple_test_multiset()::counter1: (3, 10)
simple_test_multiset()::counter1: (5, 10)
simple_test_multiset()::counter1: (7, 10)
simple_test_multiset()::counter2: (5, 10)
simple_test_multiset()::counter2: (3, 10)
simple_test_multiset()::counter2: (7, 10)
simple_test_multiset()::counter2.count({3, 10}) = 2
simple_test_multiset()::counter2.count({5, 10}) = 3
simple_test_multiset()::counter2.count({7, 10}) = 2
simple_test_multiset()::counter2.size() = 3
Note that count() here returns the number of elements within the multiset that are considered equal to the ItemKey passed in. This may be advantageous for situations where you want to ask "how many of my points are within my tolerance of a new point?"
Good luck!
Ok, so this is an interview question that I got, and only performed mediocre on at the time. I am wondering what the optimal solution is and how it is best implemented.
You are given multiple sorted lists, construct something that allows us to iterate over all these lists from the smallest to the largest element.
Example:
{ -2, 5, 10}
{ 2, 9, 11}
{ -5, 9}
-> -5, -2, 2, 5, 9, 9, 10, 11
Update:
With a bit of help from the SO chat #c-questions-and-answers and #Nican in particular, I've gotten this ship to fly somehow. I have posted my working code as an answer to allow for other solutions as well.
The answer I have posted below is still messy, and in particular I have not implemented == and != correctly. I still need help on those.
Justification for this question
Finding clean and minimalistic custom iterator implementations online is not that common. And I believe this question may serve as a good starting point for others to enhance their understanding of iterators and best practices.
I think that SortedListsIter::iterator should contain a copy of all the items, rather than reference, so that you can be ForwardIterator instead of InputIterator. You also avoid the dangling reference in the end iterator (which can be a default constructed iterator, as iterator::iterator(std::vector<SortedListIterItem<Iter> > _items = {}) : m_items(_items){};)
Two heaps may differ in order of elements, so we use std::is_permutation to determine equality
bool SortedListsIter::iterator::operator==(iterator other)
{ return std::is_permutation(m_items.begin(), m_items.end(), other.m_items.begin(), other.m_items.end()); }
C++11 alternative (4 iterator version that checks distance isn't available):
bool SortedListsIter::iterator::operator==(iterator other)
{ return (std::distance(m_items.begin(), m_items.end()) == std::distance(other.m_items.begin(), other.m_items.end()))
&& std::is_permutation(m_items.begin(), m_items.end(), other.m_items.begin()); }
Item equality is simple:
bool SortedListIterItem::operator==(SortedListIterItem other)
{ return (it_beg == other.it_beg) && (it_end == other.it_end); }
This is not a complete answer
I've implemented a partly solution to the point that it works. This is not a complete, nor correct implementation in lines with the requirements of a input_iterator. This illustrates the point, and the remaining legwork is up to whoever feels the call.
--
I just picked this up again from my notes and efforts yesterday. I've gotten some really nice help from Nican.
I'm using a heap to keep the lists inside my structure. (Which has the valid critique that I am reinventing the priority_queue). There are several things still missing here, among other things:
Copy constructor
Post-fix ++ operator
Proper == and != implementation, I'm only comparing size.
This could easily be a forward_iterator.
I got to the point where I've built my understanding of iterators. And this is as far as I'm going to take it this time around.
#include <algorithm>
#include <forward_list>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
template <typename Iter>
struct SortedListIterItem {
Iter it_beg;
Iter it_end;
/* Used by the heap to sort ascending */
bool operator<(const SortedListIterItem<Iter>& other) {
return *it_beg > *other.it_beg;
}
bool operator==(const SortedListIterItem<Iter>& other) {
return it_beg == other.it_begin && it_end == *other.it_beg;
}
SortedListIterItem<Iter>(Iter _begin, Iter _end)
: it_beg(_begin), it_end(_end){};
};
template <typename Iter>
class SortedListsIter {
// member typedefs provided through inheriting from std::iterator
class iterator {
std::vector<SortedListIterItem<Iter> > m_items;
public:
iterator(std::vector<SortedListIterItem<Iter> > _items = {})
: m_items(_items){};
iterator& operator++() {
std::pop_heap(m_items.begin(), m_items.end());
SortedListIterItem<Iter>& largest = m_items.back();
if (++largest.it_beg == largest.it_end) {
m_items.pop_back();
} else {
std::push_heap(m_items.begin(), m_items.end());
}
return *this;
}
// iterator traits
using value_type = typename Iter::value_type;
using pointer = typename Iter::pointer;
using reference = typename Iter::reference;
using iterator_category = std::input_iterator_tag;
/** A simplified comparator, which is not a correct implementation.
* While it does work for regular for loops. */
bool operator!=(iterator other) {
return (m_items.size() != other.m_items.size());
}
value_type operator*() const {
return *(m_items.front().it_beg);
};
};
std::vector<SortedListIterItem<Iter> > m_items;
public:
void add_list(Iter it_begin, Iter it_end) {
if (it_begin != it_end) {
m_items.push_back(SortedListIterItem<Iter>(it_begin, it_end));
std::push_heap(m_items.begin(), m_items.end());
}
// Ignore empty lists.
}
iterator begin() { return iterator(m_items); };
iterator end() {
std::vector<SortedListIterItem<Iter> > _items;
return iterator(_items);
};
};
int main(int argc, char** argv) {
std::forward_list<std::string> animals = {"Cat", "Dog", "Horse"};
std::forward_list<std::string> fish = {"Dolphin", "Mermaid", "Shark"};
std::forward_list<std::string> birds = {"Crow", "Duck", "Eagle"};
SortedListsIter<std::forward_list<std::string>::iterator> my_string_iter;
my_string_iter.add_list(fish.begin(), fish.end());
my_string_iter.add_list(animals.begin(), animals.end());
my_string_iter.add_list(birds.begin(), birds.end());
for (auto i : my_string_iter) {
std::cout << " " << i << ",";
}
std::cout << std::endl;
for (auto i : my_string_iter) {
std::cout << " " << i << ",";
}
std::cout << std::endl;
std::vector<int> l4 = {1, 2, 99};
std::vector<int> l5 = {-11, -4, 3};
std::vector<int> l6 = {-5, 1};
SortedListsIter<std::vector<int>::iterator> my_iter2;
my_iter2.add_list(l4.begin(), l4.end());
my_iter2.add_list(l5.begin(), l5.end());
my_iter2.add_list(l6.begin(), l6.end());
for (auto i : my_iter2) {
std::cout << " " << i << ",";
}
std::cout << std::endl;
return 0;
}
What I would really like is a container class in C++, which is exactly like the STL vector class in every way, except that the [] operator has wrapping behaviour. For example:
vector<int> myVec;
myVec.push_back(5);
myVec.push_back(10);
myVec.push_back(15);
cout << myVec[ 5] << endl; // would output 15
cout << myVec[ 1] << endl; // would output 10
cout << myVec[-2] << endl; // would output 10
Does such a container already exist, or is it possible to overload or redefine the [] operator in the vector template?
I have seen the Boost circular buffer, and it does not behave in this way.
Does such a container already exist
Not in standard library at least.
is it possible to overload or redefine the [] operator in the vector template?
No, you cannot overload or redefine [] operator of std::vector.
It is certainly possible to write a wrapper with an overloaded T& operator[](int pos) that has the behaviour that you describe. Like this:
T& operator[](int pos) {
std::vector<T>::size_type fancy_pos =
pos < 0 ? data.size() + pos
: pos - 1;
return data[fancy_pos];
}
In C++ indices for containers start from 0.
You could wrap the standard container std::vector in a class and overload operator [] such a way that the index is calculated like index = index % size() or index %= size()
You are looking for a cyclic buffer or a circular buffer.
Boost has them:
http://www.boost.org/doc/libs/1_61_0/doc/html/circular_buffer.html
They are sometimes vastly better performing than e.g. rolling your own with std::deque, see this sample from ASIO:
boost 1.55 asio tcp cpp03 chat_server example memory leaks
Update
I maintain boost::circular_buffer is probably what you /should want/ - because it abstracts away the "how" for most tasks that you'd usually want this for. However, it's dead simple to create your own adaptor type:
Live On Coliru
#include <vector>
namespace mylib {
template <typename T, typename Container = std::vector<T> >
struct circular : Container {
using Container::Container;
using Container::operator =;
auto& operator[](int i) const {
// mixed signed/unsigned modulo is undefined
while (i<0) i += Container::size();
return Container::operator[](i % Container::size());
}
auto& operator[](int i) {
while (i<0) i += Container::size();
return Container::operator[](i % Container::size());
}
};
}
#include <iostream>
template <typename Whatever>
void test(Whatever const& data) {
std::cout << data[ 5] << ", "; // would output 15
std::cout << data[ 1] << ", "; // would output 10
std::cout << data[-2] << std::endl; // would output 10
}
#include <string>
#include <deque>
int main() {
test(mylib::circular<int> { 5, 10, 15 });
test(mylib::circular<std::string> { "five", "teen", "fiteen" });
test(mylib::circular<std::string, std::deque<std::string> > { "five", "teen", "fiteen" });
test(mylib::circular<int, std::deque<float> > { 5, 10, 15 });
}
Prints:
15, 10, 10
fiteen, teen, teen
fiteen, teen, teen
15, 10, 10
Assume I have the following code:
vector<int> list;
for(auto& elem:list) {
int i = elem;
}
Can I find the position of elem in the vector without maintaining a separate iterator?
Yes you can, it just take some massaging ;)
The trick is to use composition: instead of iterating over the container directly, you "zip" it with an index along the way.
Specialized zipper code:
template <typename T>
struct iterator_extractor { typedef typename T::iterator type; };
template <typename T>
struct iterator_extractor<T const> { typedef typename T::const_iterator type; };
template <typename T>
class Indexer {
public:
class iterator {
typedef typename iterator_extractor<T>::type inner_iterator;
typedef typename std::iterator_traits<inner_iterator>::reference inner_reference;
public:
typedef std::pair<size_t, inner_reference> reference;
iterator(inner_iterator it): _pos(0), _it(it) {}
reference operator*() const { return reference(_pos, *_it); }
iterator& operator++() { ++_pos; ++_it; return *this; }
iterator operator++(int) { iterator tmp(*this); ++*this; return tmp; }
bool operator==(iterator const& it) const { return _it == it._it; }
bool operator!=(iterator const& it) const { return !(*this == it); }
private:
size_t _pos;
inner_iterator _it;
};
Indexer(T& t): _container(t) {}
iterator begin() const { return iterator(_container.begin()); }
iterator end() const { return iterator(_container.end()); }
private:
T& _container;
}; // class Indexer
template <typename T>
Indexer<T> index(T& t) { return Indexer<T>(t); }
And using it:
#include <iostream>
#include <iterator>
#include <limits>
#include <vector>
// Zipper code here
int main() {
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto p: index(v)) {
std::cout << p.first << ": " << p.second << "\n";
}
}
You can see it at ideone, though it lacks the for-range loop support so it's less pretty.
EDIT:
Just remembered that I should check Boost.Range more often. Unfortunately no zip range, but I did found a pearl: boost::adaptors::indexed. However it requires access to the iterator to pull of the index. Shame :x
Otherwise with the counting_range and a generic zip I am sure it could be possible to do something interesting...
In the ideal world I would imagine:
int main() {
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto tuple: zip(iota(0), v)) {
std::cout << tuple.at<0>() << ": " << tuple.at<1>() << "\n";
}
}
With zip automatically creating a view as a range of tuples of references and iota(0) simply creating a "false" range that starts from 0 and just counts toward infinity (or well, the maximum of its type...).
jrok is right : range-based for loops are not designed for that purpose.
However, in your case it is possible to compute it using pointer arithmetic since vector stores its elements contiguously (*)
vector<int> list;
for(auto& elem:list) {
int i = elem;
int pos = &elem-&list[0]; // pos contains the position in the vector
// also a &-operator overload proof alternative (thanks to ildjarn) :
// int pos = addressof(elem)-addressof(list[0]);
}
But this is clearly a bad practice since it obfuscates the code & makes it more fragile (it easily breaks if someone changes the container type, overload the & operator or replace 'auto&' by 'auto'. good luck to debug that!)
NOTE: Contiguity is guaranteed for vector in C++03, and array and string in C++11 standard.
No, you can't (at least, not without effort). If you need the position of an element, you shouldn't use range-based for. Remember that it's just a convenience tool for the most common case: execute some code for each element. In the less-common circumstances where you need the position of the element, you have to use the less-convenient regular for loop.
Based on the answer from #Matthieu there is a very elegant solution using the mentioned boost::adaptors::indexed:
std::vector<std::string> strings{10, "Hello"};
int main(){
strings[5] = "World";
for(auto const& el: strings| boost::adaptors::indexed(0))
std::cout << el.index() << ": " << el.value() << std::endl;
}
You can try it
This works pretty much like the "ideal world solution" mentioned, has pretty syntax and is concise. Note that the type of el in this case is something like boost::foobar<const std::string&, int>, so it handles the reference there and no copying is performed. It is even incredibly efficient: https://godbolt.org/g/e4LMnJ (The code is equivalent to keeping an own counter variable which is as good as it gets)
For completeness the alternatives:
size_t i = 0;
for(auto const& el: strings) {
std::cout << i << ": " << el << std::endl;
++i;
}
Or using the contiguous property of a vector:
for(auto const& el: strings) {
size_t i = &el - &strings.front();
std::cout << i << ": " << el << std::endl;
}
The first generates the same code as the boost adapter version (optimal) and the last is 1 instruction longer: https://godbolt.org/g/nEG8f9
Note: If you only want to know, if you have the last element you can use:
for(auto const& el: strings) {
bool isLast = &el == &strings.back();
std::cout << isLast << ": " << el << std::endl;
}
This works for every standard container but auto&/auto const& must be used (same as above) but that is recommended anyway. Depending on the input this might also be pretty fast (especially when the compiler knows the size of your vector)
Replace the &foo by std::addressof(foo) to be on the safe side for generic code.
If you have a compiler with C++14 support you can do it in a functional style:
#include <iostream>
#include <string>
#include <vector>
#include <functional>
template<typename T>
void for_enum(T& container, std::function<void(int, typename T::value_type&)> op)
{
int idx = 0;
for(auto& value : container)
op(idx++, value);
}
int main()
{
std::vector<std::string> sv {"hi", "there"};
for_enum(sv, [](auto i, auto v) {
std::cout << i << " " << v << std::endl;
});
}
Works with clang 3.4 and gcc 4.9 (not with 4.8); for both need to set -std=c++1y. The reason you need c++14 is because of the auto parameters in the lambda function.
If you insist on using range based for, and to know index, it is pretty trivial to maintain index as shown below.
I do not think there is a cleaner / simpler solution for range based for loops. But really why not use a standard for(;;)? That probably would make your intent and code the clearest.
vector<int> list;
int idx = 0;
for(auto& elem:list) {
int i = elem;
//TODO whatever made you want the idx
++idx;
}
There is a surprisingly simple way to do this
vector<int> list;
for(auto& elem:list) {
int i = (&elem-&*(list.begin()));
}
where i will be your required index.
This takes advantage of the fact that C++ vectors are always contiguous.
Here's a quite beautiful solution using c++20:
#include <array>
#include <iostream>
#include <ranges>
template<typename T>
struct EnumeratedElement {
std::size_t index;
T& element;
};
auto enumerate(std::ranges::range auto& range)
-> std::ranges::view auto
{
return range | std::views::transform(
[i = std::size_t{}](auto& element) mutable {
return EnumeratedElement{i++, element};
}
);
}
auto main() -> int {
auto const elements = std::array{3, 1, 4, 1, 5, 9, 2};
for (auto const [index, element] : enumerate(elements)) {
std::cout << "Element " << index << ": " << element << '\n';
}
}
The major features used here are c++20 ranges, c++20 concepts, c++11 mutable lambdas, c++14 lambda capture initializers, and c++17 structured bindings. Refer to cppreference.com for information on any of these topics.
Note that element in the structured binding is in fact a reference and not a copy of the element (not that it matters here). This is because any qualifiers around the auto only affect a temporary object that the fields are extracted from, and not the fields themselves.
The generated code is identical to the code generated by this (at least by gcc 10.2):
#include <array>
#include <iostream>
#include <ranges>
auto main() -> int {
auto const elements = std::array{3, 1, 4, 1, 5, 9, 2};
for (auto index = std::size_t{}; auto& element : elements) {
std::cout << "Element " << index << ": " << element << '\n';
index++;
}
}
Proof: https://godbolt.org/z/a5bfxz
I read from your comments that one reason you want to know the index is to know if the element is the first/last in the sequence. If so, you can do
for(auto& elem:list) {
// loop code ...
if(&elem == &*std::begin(list)){ ... special code for first element ... }
if(&elem == &*std::prev(std::end(list))){ ... special code for last element ... }
// if(&elem == &*std::rbegin(list)){... (C++14 only) special code for last element ...}
// loop code ...
}
EDIT: For example, this prints a container skipping a separator in the last element. Works for most containers I can imagine (including arrays), (online demo http://coliru.stacked-crooked.com/a/9bdce059abd87f91):
#include <iostream>
#include <vector>
#include <list>
#include <set>
using namespace std;
template<class Container>
void print(Container const& c){
for(auto& x:c){
std::cout << x;
if(&x != &*std::prev(std::end(c))) std::cout << ", "; // special code for last element
}
std::cout << std::endl;
}
int main() {
std::vector<double> v{1.,2.,3.};
print(v); // prints 1,2,3
std::list<double> l{1.,2.,3.};
print(l); // prints 1,2,3
std::initializer_list<double> i{1.,2.,3.};
print(i); // prints 1,2,3
std::set<double> s{1.,2.,3.};
print(s); // print 1,2,3
double a[3] = {1.,2.,3.}; // works for C-arrays as well
print(a); // print 1,2,3
}
Tobias Widlund wrote a nice MIT licensed Python style header only enumerate (C++17 though):
GitHub
Blog Post
Really nice to use:
std::vector<int> my_vector {1,3,3,7};
for(auto [i, my_element] : en::enumerate(my_vector))
{
// do stuff
}
If you want to avoid having to write an auxiliary function while having
the index variable local to the loop, you can use a lambda with a mutable variable.:
int main() {
std::vector<char> values = {'a', 'b', 'c'};
std::for_each(begin(values), end(values), [i = size_t{}] (auto x) mutable {
std::cout << i << ' ' << x << '\n';
++i;
});
}
Here's a macro-based solution that probably beats most others on simplicity, compile time, and code generation quality:
#include <iostream>
#define fori(i, ...) if(size_t i = -1) for(__VA_ARGS__) if(i++, true)
int main() {
fori(i, auto const & x : {"hello", "world", "!"}) {
std::cout << i << " " << x << std::endl;
}
}
Result:
$ g++ -o enumerate enumerate.cpp -std=c++11 && ./enumerate
0 hello
1 world
2 !