C++ 在C+中获取索引+;11 foreach循环
在C++11 foreach循环中,是否有一种方便的方法来获取当前容器项的索引,如python中的C++ 在C+中获取索引+;11 foreach循环,c++,c++11,foreach,C++,C++11,Foreach,在C++11 foreach循环中,是否有一种方便的方法来获取当前容器项的索引,如python中的enumerate: for idx, obj in enumerate(container): pass 我可以想象一个迭代器也可以返回索引或类似的内容 当然我可以有一个计数器,但迭代器通常不能保证它们在容器上迭代的顺序。如果需要索引,那么传统的for就可以很好地工作 for (int idx=0; idx<num; ++idx) { // do stuff } for(int
enumerate
:
for idx, obj in enumerate(container):
pass
我可以想象一个迭代器也可以返回索引或类似的内容
当然我可以有一个计数器,但迭代器通常不能保证它们在容器上迭代的顺序。如果需要索引,那么传统的for就可以很好地工作
for (int idx=0; idx<num; ++idx)
{
// do stuff
}
for(int idx=0;idx可以在此处找到所需功能的良好实现:
背后的想法是,您使用一个自定义迭代器构建一个包装器结构,该迭代器进行计数。下面是一个非常简单的示例性实现来说明这一想法:
#include <iostream>
#include <vector>
#include <tuple>
// Wrapper class
template <typename T>
class enumerate_impl
{
public:
// The return value of the operator* of the iterator, this
// is what you will get inside of the for loop
struct item
{
size_t index;
typename T::value_type & item;
};
typedef item value_type;
// Custom iterator with minimal interface
struct iterator
{
iterator(typename T::iterator _it, size_t counter=0) :
it(_it), counter(counter)
{}
iterator operator++()
{
return iterator(++it, ++counter);
}
bool operator!=(iterator other)
{
return it != other.it;
}
typename T::iterator::value_type item()
{
return *it;
}
value_type operator*()
{
return value_type{counter, *it};
}
size_t index()
{
return counter;
}
private:
typename T::iterator it;
size_t counter;
};
enumerate_impl(T & t) : container(t) {}
iterator begin()
{
return iterator(container.begin());
}
iterator end()
{
return iterator(container.end());
}
private:
T & container;
};
// A templated free function allows you to create the wrapper class
// conveniently
template <typename T>
enumerate_impl<T> enumerate(T & t)
{
return enumerate_impl<T>(t);
}
int main()
{
std::vector<int> data = {523, 1, 3};
for (auto x : enumerate(data))
{
std::cout << x.index << ": " << x.item << std::endl;
}
}
#包括
#包括
#包括
//包装类
模板
类枚举\u impl
{
公众:
//迭代器的运算符*的返回值
//是你将在for循环中得到的
结构项
{
尺寸指数;
typename T::value_type&item;
};
类型定义项目值\u类型;
//具有最小接口的自定义迭代器
结构迭代器
{
迭代器(类型名T::迭代器,大小T计数器=0):
它(_it),计数器(counter)
{}
迭代器运算符++()
{
返回迭代器(++it,++计数器);
}
布尔运算符!=(迭代器其他)
{
归还它!=其他。它;
}
typename T::迭代器::值\类型项()
{
归还它;
}
值类型运算符*()
{
返回值_type{counter,*it};
}
大小索引()
{
返回计数器;
}
私人:
类型名T::迭代器;
尺寸计数器;
};
枚举impl(T&T):容器(T){
迭代器begin()
{
返回迭代器(container.begin());
}
迭代器结束()
{
返回迭代器(container.end());
}
私人:
T&container;
};
//模板化的自由函数允许您创建包装器类
//方便地
模板
枚举(T&T)
{
返回枚举impl(t);
}
int main()
{
向量数据={523,1,3};
用于(自动x:枚举(数据))
{
std::cout一个简单的解决方案怎么样
int counter=0;
for (auto &val: container)
{
makeStuff(val, counter);
counter++;
}
通过添加作用域,可以使在计数器后添加代码变得更“困难”:
int counter=0;
for (auto &val: container)
{{
makeStuff(val, counter);
}counter++;}
正如@graham.reeds所指出的,正常的for
循环也是一种解决方案,其速度可能与以下方法一样快:
int counter=0;
for (auto it=container.begin(); it!=container.end(); ++it, ++counter)
{
makeStuff(val, counter);
}
最后,使用算法的另一种方法:
int counter = 0;
std::for_each(container.begin(), container.end(), [&counter](int &val){
makeStuff(val, counter++);
});
注:量程循环和正常循环之间的顺序由标准6.5.4保证。这意味着计数器能够与容器中的位置一致
如果您可以访问Boost,其范围适配器可以如下使用:
using namespace boost::adaptors;
for (auto const& elem : container | indexed(0))
{
std::cout << elem.index() << " - " << elem.value() << '\n';
}
使用名称空间boost::adapters;
用于(自动常量和元素:容器|索引(0))
{
std::coutC++17和结构化绑定使它看起来不错-当然比一些丑陋的可变lambda更好,它带有一个本地的[i=0](元素&)可变的,或者我在承认可能不是所有东西都应该被塞进中之前所做的任何事情
等。-而不是其他需要计数器的解决方案,计数器的作用域不在循环中
for(auto[it,end,i]=std::tuple{container.cbegin(),container.cend(),0};
它!=结束;++it,++i)
{
//同时需要“它”和“我”的东西
}
如果您经常使用此模式,则可以将其设置为通用模式:
template <typename Container>
auto
its_and_idx(Container&& container)
{
using std::begin, std::end;
return std::tuple{begin(container), end(container), 0};
}
// ...
for (auto [it, end, i] = its_and_idx(foo); it != end; ++it, ++i)
{
// something
}
模板
汽车
its_和_idx(容器和容器)
{
使用std::begin、std::end;
返回std::tuple{begin(container),end(container),0};
}
// ...
for(auto[it,end,i]=its_和_idx(foo);it!=end;++it,++i)
{
//某物
}
C++标准提案建议添加视图::enumerate
,这将提供一个范围视图,该视图向迭代它的用户提供对元素的引用和元素的索引
我们提出了一个视图enumerate
,其值类型为struct
,有两个成员index
和value
,分别表示调整范围内元素的位置和值
[……]
此特征以Python、Ru锈、Go(在语言中)的形式存在,在许多C++库中:<代码> Ranges -V3,<>代码>愚蠢> <代码>,代码> Boo::范围< /COD>(<代码>索引< /C> >)
这一特征的存在与否是反复出现的问题的主题
嘿,看!我们很有名。不,但使用boost并不难。Range的zip
和boost的计数迭代器一起达到这个目的。复制到某个东西,答案是自己计数。这个答案怎么样:听起来不错,但它只适用于顺序容器,而不适用于关联容器。对于associTive容器您需要的是键,而不是索引。@EdChum:关联容器的迭代器已经返回键和值。这可能会很慢。例如,可能是链表,但没有提到性能,也没有提到链表。为什么迭代器在链表上会更快?因为它可以在内部保存当前节点和值从那里开始。不需要随机访问。因为链表不支持随机访问。而且它不适用于无序容器,例如set
和map
当您使用迭代器时,可以使用std::distance(container.begin(),it)
而不是计数器变量。@sigalor:根据迭代器的类型,std::distance可能是O(n),它不如计数器(O(k))好.@AdrianMail您的上一个示例似乎没有增加计数器。谢谢,应该现在修复。@sigalor是的,但这可以说是浪费,特别是当有很多元素和/或容器是迭代器算法昂贵的容器时。警告:信不信由你,如果