假设我们需要遍历一个容器。传统的for循环如下所示:

for (auto it = container.begin(), end = container.end();
     it != end;
     ++it)
{
    doStuff(*it);
}

而基于范围的for如下所示:
for (auto& element : container)
{
    doStuff(element);
}

现在,在开发的某个时刻,我们意识到出于某种原因,我们需要在这些循环迭代中增加其他内容。

需要增加的可能是各种各样的东西。例如,如果我们将相关数据存储在相同大小的其他容器中,那么在进行迭代时,我们可能也需要将迭代器增加到这些容器中(尽管我希望标准库的 future 版本能够使我们做更多的事情)通过结构化绑定(bind)和标准版本的boost::range::combine或其他方式来表达)。

在下面,为简单起见,我们假设要为每个元素分配一个ID,因此需要增加的只是一个计数器。

现在,传统循环看起来像这样:
unsigned int elementID = 0u;
for (auto it = container.begin(), end = container.end();
     it != end;
     ++it, ++elementID)
{
    doStuff(*it, elementID);
}

几乎不需要更改任何内容,并且在++elementID之后添加++it可以保证无论每次迭代后计数器如何递增。即使另一个程序员修改了循环的主体,并说通过continue在特定条件下提前进入下一个迭代,也不会冒着他们忘记增加计数器或类似内容的风险。

现在,据我所知,使用基于范围的for,进行增量的唯一方法是执行以下操作:
unsigned int elementID = 0u;
for (auto& element : container)
{
    doStuff(element, elementID);
    ++elementID;
}

也就是说,将增量放在循环体内。

elementID而言,它的表现力较差(即,如果代码的主体很长,那么阅读该代码的人将不会一眼就看到我们也在迭代elementID),并且也不能保证我上面提到的ve,因此也容易出错。

真的没有其他方法可以实现基于范围的for吗?还是有一种方法可以按照我根本不知道的for(auto& element : container; ++elementID){...}编写东西?

在人们回答之后进行编辑

内文建议使用boost的BOOST_SCOPE_EXIT_ALL,就非 native 解决方案而言,这与我所想到的最接近。

我不确定实际的实现方式,但是我猜这依赖于lambda和析构函数。我写这个来测试一下:
template <typename T>
class ScopeExitManager
{
public:
    ScopeExitManager(T const& functionToRunOnExit) : _functionToRunOnExit(functionToRunOnExit)
    {
    }

    ~ScopeExitManager()
    {
        _functionToRunOnExit();
    }

private:
    T _functionToRunOnExit;
};


template <typename T>
ScopeExitManager<T> runOnScopeExit(T const& functionToRunOnExit)
{
    return {functionToRunOnExit};
}

然后,我可以按照以下方式写点东西:
unsigned int elementID = 0u;
for (auto& element : container)
{
    // Always at the beginning of the loop
    auto scopeExitManager = runOnScopeExit([&elementID](){++elementID;});

    // Actual body of the loop
    doStuff(element, elementID);
}

这是表达性的,并保证elementID将增加。这很棒!

最佳答案

完成此操作的另一种方法是使用类似Boost.ScopeExit的方法,例如:

unsigned int elementID = 0u;
for (auto& element : container)
{
    BOOST_SCOPE_EXIT_ALL(&) { ++elementID; };
    doStuff(element, elementID);
}

10-04 14:55