跳过 unordered_map 的第一次迭代

Skip first iteration over unordered_map

在使用 autofor 循环中,迭代器迭代 unordered_map。像这样:

using RuleIndex = std::unordered_map<uint, Symbol*>;
RuleIndex rule_index;
for(const auto & rule_pair : rule_index ) {
   std::cout << rule_pair.first << ": ";
   printList(rule_pair.second, 0);
   std::cout << std::endl;
}

假设所有变量都已正确定义,因为代码运行良好。我的问题是,如何排除第一次迭代?例如,地图包含 3 行,当前循环迭代 0、1、2。我只想迭代 1 和 2。

bool is_first_iteration = true;
for(const auto & rule_pair : rule_index) {
   if (std::exchange(is_first_iteration, false)) continue;
   std::cout << rule_pair.first << ": ";
   printList(rule_pair.second, 0);
   std::cout << std::endl;
}

std::exchange 调用将 false 分配给 is_first_iteration 和 returns 先前的值。这实际上是 the paper proposing std::exchange for C++14 中讨论的用例之一。该论文还展示了一个参考实现,如果您坚持使用 C++11,则可以使用它。

如果您不能使用 std::exchange(由于 C++11 的限制),这个简单的解决方案也可以工作:

bool is_first_iteration = true;
for (const auto & rule_pair : rule_index) 
{
  if (is_first_iteration) 
  {
    is_first_iteration = false;
    continue;
  }
  std::cout << rule_pair.first << ": ";
  printList(rule_pair.second, 0);
  std::cout << std::endl;
}

我有时使用的一个简洁的 C++11 选项,它也保留了一个有时很方便的计数器。我在下面展示了 if (i++),它依赖于 0 转换为 false,而其他数字转换为 true,但如果你是,你可以输入 if (++i > 1)更舒服:

size_t i = 0;
for (const auto & rule_pair : rule_index)
    if (i++)
    {
        ...
    }

...或if (++i == 1) continue;...如果您愿意...

虽然易于编写、简洁且有时很有帮助,但与布尔版本相比,这些可能更难优化 - 如果您关心的话,请进行基准测试。


另一种有时有用的方法:

for (const auto & rule_pair : rule_index)
    if (&rule_pair != &*std::begin(rule_index))
    {
        ...
    }