在c++ 11 foreach循环中获取index
Get index in C++11 foreach loop
是否有一种方便的方法来获取c++ 11 foreach循环中当前容器条目的索引,如python中的enumerate
:
for idx, obj in enumerate(container):
pass
我可以想象一个迭代器也可以返回索引或类似的东西。
当然可以有一个计数器,但是迭代器通常不能保证它们在容器上迭代的顺序。
您所要求的功能的一个很好的实现可以在这里找到:
https://github.com/ignatz/pythonic背后的思想是,您构建一个包装器结构体,并使用自定义迭代器进行计数。下面是一个非常简单的示例实现来说明这个想法:
// Distributed under the terms of the GPLv2 or newer
#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;
}
}
简单的解决方案如何:
int counter=0;
for (auto &val: container)
{
makeStuff(val, counter);
counter++;
}
您可以通过添加作用域来使在计数器之后添加代码变得更"困难":
int counter=0;
for (auto &val: container)
{{
makeStuff(val, counter);
}counter++;}
@graham。芦苇指出,正常的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,则可以这样使用它的范围适配器:
#include <boost/range/adaptor/indexed.hpp>
using namespace boost::adaptors;
for (auto const& elem : container | indexed(0))
{
std::cout << elem.index() << " - " << elem.value() << 'n';
}
源代码(其中还有其他示例)
c++ 17和结构化绑定使这看起来不错-当然比一些丑陋的带有局部[i = 0](Element&) mutable
的可变lambda或任何我在承认可能不是所有东西都应该硬塞进for_each()
等之前所做的要好-并且比其他解决方案需要for
循环之外的计数器。
for (auto [it, end, i] = std::tuple{container.cbegin(), container.cend(), 0};
it != end; ++it, ++i)
{
// something that needs both `it` and `i`ndex
}
如果你经常使用这个模式,你可以把它变成通用的:
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
}
c++标准提案P2164建议增加views::enumerate
,它将提供一个范围的视图,为迭代它的用户提供对元素的引用和元素的索引。
我们提出一个值类型为
struct
的视图enumerate
,它有两个成员index
和value
,分别表示在适应范围内的元素的位置和值。[…]
此功能以某种形式存在于Python, Rust, Go(返回到语言中)以及许多c++库中:
ranges-v3
,folly
,boost::ranges
(indexed
)。是否存在此特性是反复出现的stackoverflow问题的主题。
嘿,瞧!我们有名。
如果你需要索引,那么传统的for就可以了。
for (int idx=0; idx<num; ++idx)
{
// do stuff
}
- 在提升multi_index容器中,是否定义了"default index"?
- C++为构建时间获取QDateTime的可靠方法
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 使用指针从C++中的数组中获取最大值
- 如何获取std::result_of函数的返回类型
- 如何在openssl-ecc中获取十六进制格式的私钥
- 使用Unreal C++获取VR耳机的世界位置/方向
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 从C字符串中获取奇怪的字符串长度
- 为什么我的for循环不能正确获取argv
- 从python中调用C++函数并获取返回值
- 如何获取一个数字的前3位
- 获取字符串的长度并将其分配给数组
- 无法获取菜单选择以运行函数.C++
- 数组长度,为什么从命令行获取时不能使用它?
- Boost Spirit,获取迭代器内部语义动作
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 通过迭代器获取 set 元素的"index"
- 在c++ 11 foreach循环中获取index