Victor
Victor

Reputation: 688

How to get the index of an element of a std::vector from the reference to one of it's items?

How would you elegantly (and in a modern C++ way) write a function that returns the index of a vector element, taking as argument this vector, and a reference to one of its elements ?

Exceptions handling would be appreciated.

#include <vector>

template <class T>
std::size_t GetIndexFromRef(std::vector<T> &vec, T &item)
{
...
};

Upvotes: 3

Views: 870

Answers (1)

Quentin
Quentin

Reputation: 63154

This does the trick:

template <class T>
std::size_t GetIndexFromRef(std::vector<T> const &vec, T const &item)
{
    T const *data = vec.data();

    if(std::less<T const *>{}(&item, data) || std::greater_equal<T const *>{}(&item, data + vec.size()))
        throw std::out_of_range{"The given object is not part of the vector."};
    
    return static_cast<std::size_t>(&item - vec.data());
};

I'm using std::less and std::greater_equal, because ([comparisons.general§2]):

For templates less, greater, less_­equal, and greater_­equal, the specializations for any pointer type yield a result consistent with the implementation-defined strict total order over pointers ([defns.order.ptr]).
[Note 1: If a < b is well-defined for pointers a and b of type P, then (a < b) == less<P>()(a, b), (a > b) == greater<P>()(a, b), and so forth. — end note]

Otherwise, performing the comparison with an object that isn't part of the vector would be UB.

Upvotes: 7

Related Questions