Is this a legal way to find the position of an element in a vector?
I have the following loop in my code:
for (const auto& item : vec) {...}
To find the position item
in vec
I do:
size_t pos = ((size_t)&item-(size_t)vec.data())/sizeof(item);
But it feels like "C" (as opposed to "C ++").
I know I can achieve this goal if I change my loop format to one of the following:
-
for (size_t i = 0; i < vec.size(); i++) {...}
-
for (auto it = vec.begin(); it != vec.end(); it++) {...}
But I would like to refrain from that.
Bottom questions:
- Is my method a guaranteed locale?
- Is there a "C ++" way to do this without changing the loop format?
Thank.
source to share
But I would like to refrain from that.
Index / iterator looping is what you need here. Why do you refrain from doing this?
Is my method a guaranteed locale?
Just the fact that you have to ask this question makes your method objectionable compared to an index / iterator loop. Regardless, I see no reason why your method should fail.
Is there a "C ++" way to do this without changing the loop format?
The most idiomatic C ++ way is to loop over an index / iterator. If you want a more convenient version, you can wrap the logic in a higher-order function that exposes the element as well:
template <typename Container, typename F>
void for_each_with_index(Container&& c, F&& f)
{
for(std::size_t i = 0; i < c.size(); ++i)
{
f(c[i], i);
}
}
Using:
std::vector<item> v{/* ... */};
for_each_with_index(v, [](auto& item, std::size_t index)
{
/* ... */
});
source to share
You don't need to inject types like in your example:
size_t pos = ((size_t)&item-(size_t)vec.data())/sizeof(item);
You can make pointer arithmetic more simplistic like this:
#include <iostream>
#include <vector>
int main() {
std::vector<int> test { 0, 1, 2, 3, 4, 5, 6 };
for(const auto& elem : test) {
const auto pos = &elem - test.data();
std::cout << "Element at position " << pos << " is: " << elem << std::endl;
}
return 0;
}
The reason it works is because the type &elem
is equal const int*
and the return type test.data()
is int*
, so pointer arithmetic works fine on them.
Note : if you forgot the reference operator ( &
) in a for
range based loop , the above example will not work:
for(const auto elem : test) { /* ... */ } // Warning: elem is a copy!
source to share
If you really know how to do this in C ++ without significantly changing the loop format given the inclusion of cpp itertools: https://github.com/ryanhaining/cppitertools/blob/master/README.md . This is your only hope!
vector<int> vec{2, 4, 6, 8};
for (auto&& e : enumerate(vec)) {
cout << e.index
<< ": "
<< e.element
<< '\n';
}
It provides many more tools, drawing inspiration from python, which is known for having very good repetition techniques. You can also iterate over two identical size vectors, de-nested for loops, etc.
Strictly speaking, you can also implement enumeration yourself. It's not that hard, but it is quite a lot of template lines.
source to share