这是查找向量中元素位置的合法方法吗?

Is this a legitimate way to find the position of an element in a vector?

本文关键字:方法 位置 查找 向量 元素      更新时间:2023-10-16

我的代码中有以下循环:

for (const auto& item : vec) {...}

为了找到itemvec中的位置,我做:

size_t pos = ((size_t)&item-(size_t)vec.data())/sizeof(item);

但它感觉有点"C"(与"C++"相对(。

我知道如果我将循环格式更改为以下任一格式,则可以达到此目的:

  • for (size_t i = 0; i < vec.size(); i++) {...}
  • for (auto it = vec.begin(); it != vec.end(); it++) {...}

但我想避免这样做。

底线问题:

  1. 我的方法是否由语言标准保证?
  2. 有没有更"C++"的方法可以在不更改循环格式的情况下做到这一点?

谢谢。

但我想避免这样做。

循环索引/迭代器正是您在这里需要的。你为什么不这样做?


我的方法是否由语言标准保证?

事实上,你必须问这个问题,这使得你的方法与索引/迭代器循环相比是不可取的。无论如何,我看不出您的方法失败的任何原因。


有没有一种更"C++"的方法可以在不更改循环格式的情况下做到这一点?

最惯用的C++方法是循环索引/迭代器。如果你想要一个更高级的版本,你可以将逻辑包装在一个高阶函数中,该函数也提供该项目:

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);
    }
}

用法:

std::vector<item> v{/* ... */};
for_each_with_index(v, [](auto& item, std::size_t index)
{ 
    /* ... */ 
});

魔杖盒上的现场示例

您不需要像示例中那样强制转换类型:

size_t pos = ((size_t)&item-(size_t)vec.data())/sizeof(item);

您可以执行更简单的指针算术,如下所示:

#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;
}

它之所以有效,是因为&elem的类型是const int*的,而返回的test.data()类型是int*的,因此指针算法在它们上工作正常。


注意:如果您在基于范围的循环中忘记了引用运算符(& for(,则上面的示例将不起作用:

for(const auto elem : test) { /* ... */ } // Warning: elem is a copy!

如果您真的渴望在不大幅更改循环格式的情况下在C++中执行此操作,请考虑合并 cpp 迭代工具:https://github.com/ryanhaining/cppitertools/blob/master/README.md。这是你唯一的希望!

vector<int> vec{2, 4, 6, 8};
for (auto&& e : enumerate(vec)) {
    cout << e.index
         << ": "
         << e.element
         << 'n';
}

它提供了更多的工具,从python中汲取灵感,python以具有非常好的迭代方式而闻名。您还可以一起迭代两个相同大小的向量,取消嵌套嵌套循环等。

严格来说,你也可以自己实现枚举。这并不难,但它是相当多的样板。