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.

+3


source to share


3 answers


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)
{ 
    /* ... */ 
});

      

live example in wandbox

+4


source


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!

      

+3


source


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.

+1


source







All Articles