这里有很多很好的答案。将它们组合在一起,这是一个小型库套件,它允许通过指针或引用计算项目的索引。
作为额外的好处,调用者可以选择提供一个策略对象,如果元素不在容器中,则执行该对象。
#include <stdexcept>
#include <cassert>
#include <vector>
struct exception_policy
{
[[noreturn]]
std::size_t out_of_range() const
{
throw std::out_of_range("index_of_element");
}
};
struct assertion_policy
{
std::size_t out_of_range() const
{
assert(!"out of range");
return _fallback.out_of_range();
}
exception_policy _fallback {};
};
struct zero_policy
{
std::size_t out_of_range() const
{
return 0;
}
};
template<class T, class A, class Policy = exception_policy>
std::size_t index_of_element(std::vector<T, A> const& vec,
typename std::vector<T, A>::const_pointer pitem,
Policy policy = Policy{})
{
auto pbegin = vec.data();
auto pend = pbegin + vec.size();
if (pitem < pbegin or pitem >= pend)
{
return policy.out_of_range();
}
else
{
return std::distance(pbegin, pitem);
}
}
template<class T, class A, class Policy = exception_policy>
std::size_t index_of_element(std::vector<T, A> const& vec,
typename std::vector<T, A>::const_reference item, Policy policy = Policy{})
{
return index_of_element(vec, std::addressof(item), policy);
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8 };
auto px = std::addressof(v[5]);
auto& rx = *px;
try {
// use default policy of throwing out_of_range...
auto i = index_of_element(v, rx);
assert(i == 5);
}
catch(...)
{
assert(!"should not throw");
}
try {
auto i = index_of_element(v, px);
assert(i == 5);
}
catch(...)
{
assert(!"should not throw");
}
auto py = v.data() + 1000; // out of bounds
try {
auto i = index_of_element(v, py);
assert(!"should have thrown");
}
catch(std::out_of_range const& e)
{
// success
}
catch(...)
{
assert(!"should not throw this");
}
// specify a custom policy
auto i = index_of_element(v, ry, zero_policy());
assert(i == 0);
}