Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 循环范围内的访问索引_C++_C++11 - Fatal编程技术网

C++ 循环范围内的访问索引

C++ 循环范围内的访问索引,c++,c++11,C++,C++11,我有一个对象向量,正在使用循环的范围遍历它。我使用它从对象打印函数,如下所示: vector<thisObject> storedValues; //put stuff in storedValues for(auto i:storedValues) { cout<<i.function(); } 我本来打算使用一个计数器,每次都增加一个,但这似乎效率很低。有更好的办法吗?你不能。索引是向量的特定概念,而不是集合的通用属性。另一方面,基于范围的循环是迭代任何集合的

我有一个对象向量,正在使用循环的范围遍历它。我使用它从对象打印函数,如下所示:

vector<thisObject> storedValues;
//put stuff in storedValues
for(auto i:storedValues)
{
   cout<<i.function();
}
我本来打算使用一个计数器,每次都增加一个,但这似乎效率很低。有更好的办法吗?

你不能。索引是向量的特定概念,而不是集合的通用属性。另一方面,基于范围的循环是迭代任何集合的每个元素的通用机制

如果确实希望使用特定容器实现的详细信息,只需使用普通循环:

for (std::size_t i = 0, e = v.size(); i != e; ++i) { /* ... */ }

重复这一点:基于范围的循环用于操纵任何集合的每个元素,其中集合本身并不重要,循环体中从未提及容器。它只是你工具箱中的另一个工具,你不会被迫将它用于任何事情。相比之下,如果您想要改变集合(例如移除或洗牌元素),或者使用有关集合结构的特定信息,请使用普通循环。

我创建了一个预处理器宏(通过@Artyer大大简化),它以相对干净的方式为您处理此问题:

#define for_indexed(...) for_indexed_v(i, __VA_ARGS__)
#define for_indexed_v(v, ...) if (std::size_t v = -1) for (__VA_ARGS__) if ((++v, true))
用法示例:

std::vector<int> v{1, 2, 3};
for_indexed (auto const& item : v) {
    if (i > 0) std::cout << ", ";
    std::cout << i << ": " << item;
}
额外的控制流逻辑应该在任何非调试构建中进行优化。剩下的是一个相对易于阅读的循环语法

2020注意:使用基于lambda的解决方案可能比使用宏欺骗更明智。当然,语法不会是“干净”的,但它将具有可识别为实际C++语法的优点。选择权在你

更新2017/05/28:制造
中断语句工作正常
更新2019/01/28:将
放在宏名称中,以便单词
索引
是有效的变量名称。我怀疑
是否会导致任何冲突。

更新2020/12/23:大大简化(感谢@Artyer)

使用
range-v3
<代码> Rang-V3是由ISO C++委员会成员Eric Niebler设计并实现的下一代范围库,预期和将来有望在C++标准中合并。 通过使用
range-v3
OP的问题可以很容易地解决:

使用ranges::v3::view::zip;
使用ranges::v3::view::ints;
对于(auto&&[i,idx]:zip(存储值,整数(0u))){

老实说,这很简单,只要找出你可以减去地址:)

&i将引用内存中的地址,它将从一个索引到另一个索引递增4,因为它包含定义的向量类型中的整数。现在&value[0]引用第一点,当减去2个地址时,两个地址之间的差值分别为0,4,8,12,但实际上是减去整数类型的大小,通常为4字节。 所以在对应关系中,0=0分,4=1分,8=2分,12=3分

这是一个向量

vector<int> values = {10,30,9,8};

for(auto &i: values) {

cout << "index: " <<  &i  - &values[0]; 
cout << "\tvalue: " << i << endl;

}
向量值={10,30,9,8};
用于(自动和输入:值){

cout这是c++17的预处理器宏版本的更新版本。与手动使用索引编写循环相比,Clang生成相同的调试和优化代码。MSVC生成相同的优化代码,但在调试中添加了一些额外的指令

#为_index_v(i,u VA_ARGS_uu)定义_index(…)
#为(u VA_ARGS_uuu)定义索引(i,…)if(size_t i#u next=0;true)if(size_t i=i#u next++true)
我试图深入研究MSVC在调试版本中添加的额外代码,我不太确定它的用途。它在循环开始时添加了以下内容:

        xor     eax, eax
        cmp     eax, 1
        je      $LN5@for_i

这将完全跳过循环。使用的示例:

您可以使用以下视图的
枚举:

std::向量存储值;
for(auto const&[idx,value]:存储值|范围::视图::枚举){

std::难道你认为递增一个计数器变量效率很低吗?@honk也许用词不好。我认为可能有更有效的方法。@Kyryx这肯定属于微优化的范畴。除非你100%确定确实需要微优化,否则永远不要进行微优化(因为在许多情况下,它们实际上会损害整体性能).我现在没有访问C++11编译器的权限,但它不是这样工作的:
cout甚至在考虑计数器的性能影响之前,您使用的基于范围的for循环正在复制元素,您最好使用引用和递增计数器,或者使用良好的ol'for循环…谢谢您的回复ponse.我对基于范围的循环有点过分兴奋了。你通常会这样保存结尾吗?循环不变优化应该会解决你调用size()时遇到的任何问题很多,在现代编译器中。@Dave:也许,也许不是。有时我更喜欢明确地说明这一点,而且这是一种统一的风格,我可以在任何情况下使用(例如,对于迭代器).Range-based for循环与集合无关。它们操纵范围的每个元素。也就是说,如果定义范围的迭代器至少是ForwardIterator-s,那么范围的开始和实际位置之间的距离也会得到很好的定义。@David:类似这样的循环头的另一个用例是通过在循环体中定义
std::size\t ri=e-i-1;
可以很容易地逆转迭代。这有时很方便。以两个下划线开头的名称是为实现保留的。自己使用它们是未定义的行为。我知道这一点,但我想使用没有程序员会明智地在其应用程序中使用的名称实际代码。我会更改它们。这是如此聪明,对这个问题的回答如此完美,它绝对值得成为选择的答案。只有3个
for
s是正确的
vector<int> values = {10,30,9,8};

for(auto &i: values) {

cout << "index: " <<  &i  - &values[0]; 
cout << "\tvalue: " << i << endl;

}
int values[]= {10,30,9,8};

for(auto &i: values) {

cout << "index: " <<  &i  - &values[0];
cout << "\tvalue: " << i << endl;

}
        xor     eax, eax
        cmp     eax, 1
        je      $LN5@for_i
std::vector<thisObject> storedValues;
for (auto const& [idx, value] : storedValues | ranges::view::enumerate) {
  std::cout << idx << ": " << value << '\n';
}
std::vector<thisObject> storedValues;
for (size_t idx = 0; auto value : storedValues) {
  std::cout << idx << ": " << value << '\n';
  ++idx;
}