我的个人偏好:只需保留额外的索引。 它已经很清晰了,而且如果您在循环内部有一个if()
,您还可以轻松跳过计数:
std::list<std::string> items;
{
int i = 0;
for (auto & item : items) {
if (some_condition(item)) {
item += std::to_string(i);
++i;
}
}
}
请确保在循环附近使用额外的 { }
创建一个嵌套作用域,使 i
计数器保持接近循环。此外,后增操作符含义模糊。
替代方案:我希望有一个基于范围的 index_for
语言结构,可以提供自动计数器 i
,但是目前不是这种情况。
然而,如果您绝对、坚定地坚持要使用一些好的包装器,实际上看一下您的循环语义是非常有启发性的,即使用一对 std::list
迭代器和一个 boost::counting_iterator
的 std::transform
。
std::transform(
begin(items), end(items),
boost::counting_iterator<int>(0),
begin(items),
[](auto const& elem, auto i) {
return elem + std::to_string(i);
});
这个有4个参数的
std::transform
有时被称为
zip_with
,因此有一些评论建议使用
boost::zip_iterator
与
list
和
counting_iterator
一起使用。
您可以创建一些不错的基于范围的包装器以使代码更加简洁:
template<class Range, class T, class BinaryOp>
void self_transform(Range& rng, T value, BinaryOp op)
{
auto i = value;
for (auto& elem : rng) {
elem = op(elem, i);
++i;
}
}
可以更简洁地称之为:
self_transform(items, 0, [](auto const& elem, auto i) {
return elem + std::to_string(i);
});
实时示例。
boost
库提供了计数迭代器和zip迭代器:使用zip函数将元素的数量与元素范围进行打包,然后迭代该序列,并提取每个元素及其索引。遗憾的是,结果不太美观。 - Yakk - Adam Nevraumontfor(auto z = std::make_pair(items.begin(), 0); z.first != items.end(); ++z.first, ++z.second) {}
像邪恶博士一样,用这段代码:for(auto z = std::make_pair(items.begin(), 0); z.first != items.end(); ++z.first, ++z.second) {}
- Captain Obvliousstd::size_t
代替int
--它更能表达意图(非负大小-与任意/可能为负的整数相反),更加普及和习惯化(C和C++ std库都将其用于计数、索引和大小),并且保证具有足够大的存储空间(标准仅保证int
可以表示16位宽度的数字,对于有符号类型而言,即值高达32767:en.cppreference.com/w/cpp/language/types#Integer_types)。 - Matt