其实这是两个相关的问题。
我知道 C++11 中有一种新语法,用于基于范围的
for
循环,其形式为:
//v is some container
for (auto &i: v){
// Do something with i
}
第一个问题:我如何推断我在这个循环中的哪个迭代? (假设我想在位置 j 处用值 j 填充向量)。
第二个问题:我想知道是否还有其他方法可以编写以下形式的循环
for (int i=0; i<100; i++) { ... }
我发现这种编写方式有点麻烦,而且我经常这样做,我希望有一个更简洁的语法。 大致意思是:
for(i in [0..99]){ ... }
那就太好了。
对于这两个问题,我想避免使用额外的库。
第一个答案:你不知道。您使用了一个简单的构造来实现一个简单的目的;如果您有更复杂的需求,您将需要更复杂的东西。
第二个答案:您可以创建一个产生连续整数值的迭代器类型,以及一个给出一系列整数值的“容器”类型。除非你有充分的理由自己这么做,Boost 有这样的事情:
#include <boost/range/irange.hpp>
for (int i : boost::irange(0,100)) {
// i goes from 0 to 99 inclusive
}
C++20更新:
使用扩展的 for 循环初始化语法:
std::vector v = {1, 1, 1};
for (size_t pos = 0; auto& i : v) {
i = pos;
++pos;
}
将此用于 C++11:
size_t pos = 0;
for (auto& i : v) {
i = pos;
++pos;
}
(是的,你可以写
i = pos++
,但我认为循环中还会发生更多事情。只需将 ++pos
作为循环体中的最后一条语句即可。)
(Boost很好,但没有被普遍接受。)
对于第一个问题,答案非常简单:如果您需要迭代计数,请不要使用抽象迭代计数的语法结构。只需使用普通的
for
循环,而不是基于范围的循环。
对于第二个问题,我认为标准库中当前没有任何内容,但您可以使用
boost::irange
来解决它:
for (int i : boost::irange(0, 100))
您可以使用 Boost.Range 完成这两件事:http://boost.org/libs/range
boost::adaptors::indexed
:元素值和索引boost::irange
:整数范围为了简洁起见(并且为了让事情变得有趣一点,因为
boost::irange
已经被单独演示),这里有一个示例代码,演示了这些功能协同工作:
// boost::adaptors::indexed
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
#include <boost/range/adaptor/indexed.hpp>
// boost::irange
// http://www.boost.org/doc/libs/master/libs/range/doc/html/range/reference/ranges/irange.html
#include <boost/range/irange.hpp>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> input{11, 22, 33, 44, 55};
std::cout << "boost::adaptors::indexed" << '\n';
for (const auto & element : input | boost::adaptors::indexed())
{
std::cout << "Value = " << element.value()
<< " Index = " << element.index()
<< '\n';
}
endl(std::cout);
std::cout << "boost::irange" << '\n';
for (const auto & element : boost::irange(0, 5) | boost::adaptors::indexed(100))
{
std::cout << "Value = " << element.value()
<< " Index = " << element.index()
<< '\n';
}
return 0;
}
输出示例:
boost::adaptors::indexed
Value = 11 Index = 0
Value = 22 Index = 1
Value = 33 Index = 2
Value = 44 Index = 3
Value = 55 Index = 4
boost::irange
Value = 0 Index = 100
Value = 1 Index = 101
Value = 2 Index = 102
Value = 3 Index = 103
Value = 4 Index = 104
如果
v
是向量(或任何 std
连续容器),则
for(auto& x : v ) {
size_t i = &x-v.data();
x = i;
}
会将第 i 个条目设置为值
i
。
计数的输出迭代器相当容易编写。 Boost 有一个,并且有一个易于生成的范围,称为
irange
。
提取容器的索引相对容易。我编写了一个名为
indexes
的函数,它可以接受一个容器或一系列整数,并在相关范围内生成随机输出迭代器。
这给你:
for (size_t i : indexes(v) ) {
v[i] = i;
}
Boost 中可能有一个等效的容器到索引范围函数。
如果您两者都需要,并且不想做这项工作,则可以写一个拉链。
for( auto z : zip( v, indexes(v) ) ) {
auto& x = std::get<0>(z);
size_t i = std::get<1>(z);
x = i;
}
其中
zip
接受两个或多个可迭代范围(或容器),并生成元素的 iterator_traits<It>::reference
元组的范围视图。
这里是 Boost zip 迭代器:http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html - 很可能有一个 Boost zip 范围可以处理上述语法
zip
功能。
对于第二个问题:
还有另一种方法,但我不会使用或推荐它。但是,为了快速设置测试,您可以编写:
如果您不想使用库并且只需提供可以编写的范围的上限即可:
for (auto i:vector<bool>(10)) {
cout << "x";
}
这将创建一个大小为 10 且具有未初始化值的布尔向量。使用
i
循环这些单位化值(not 使用 i
也是如此),它将打印 10 次“x”。
对于第二个问题,如果您使用的是最新的 Visual Studio 版本,请键入 'if',然后按 Tab、Tab 和 Tab 填写初始值、步进等。