【问题标题】:C++ map erase using forward and reverse iterators使用正向和反向迭代器的 C++ 映射擦除
【发布时间】:2016-09-03 20:02:56
【问题描述】:

我有一个这样的模板函数

template<typename T>
void foo(T start , T end)
{
  while(start != end)
  {
     if(cond)
       m.erase(start);
    start++;
  }

}

现在我必须同时传递正向和反向迭代器作为类型名。两个单独的调用,一个是正向的,一个是反向的迭代器。我该怎么做呢 ?

【问题讨论】:

  • 为什么要制造人为问题?传入兼容的迭代器。
  • 然后我需要两个单独的函数,并且每当发生变化时,我必须记住同时更改两个函数

标签: c++ templates iterator maps reverse-iterator


【解决方案1】:

首先,让我重申一下 LogicStuff 的评论:您真的应该尝试传入兼容的迭代器。

如果你真的真的真的别无选择,只能按照你现在的方式去做,你可以使用一些模板函数:

#include <vector>
#include <iostream>

// Used when both iterators have the same type
template <typename T>
void foo(T begin, T end)
{
  for (; begin != end; ++begin)
  {
    std::cout << " " << *begin;
  }
}

// Overload for a forward begin and reverse end
template <typename T>
void foo(T begin, std::reverse_iterator<T> end)
{
  foo(begin, end.base());
}

// Overload for a reverse begin and forward end
template <typename T>
void foo(std::reverse_iterator<T> begin, T end)
{
  foo(begin, std::reverse_iterator<T>(end));
}

int main()
{
  std::vector<int> v { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  foo(v.begin(), v.end()); std::cout << std::endl;
  foo(v.begin(), v.rbegin()); std::cout << std::endl;
  foo(v.rbegin(), v.begin()); std::cout << std::endl;
  foo(v.rbegin(), v.rend()); std::cout << std::endl;
}

See it running on ideone.

在这里,我将反向迭代器转换为正向迭代器。 This SO post gives you more details about that。但是仔细阅读那篇文章,里面有龙。我上面的例子只是输出数字,并没有修改底层容器。而且我不检查迭代器的有效性,也不做任何边界检查。对于您自己的情况,请确保您测试所有边缘情况(迭代器位于或超出容器的开头/结尾;非一个错误等)。

另外,请注意,在您的示例代码中,对 erase() 的调用会使迭代器无效,因此您应该像这样编写循环体:

if (cond) {
  // guarantees to return an iterator to the element following
  // the erased element.
  start = m.erase(start);
} else {
  ++start;
}

编辑:如果您要求迭代器始终转换为它们的正向等效项,您可以更改最后一个重载并添加另一个:

template <typename T>
void foo(std::reverse_iterator<T> begin, T end)
{
  foo(end, begin.base()); // Note: order of iteration reversed!
}

template <typename T>
void foo(std::reverse_iterator<T> begin, std::reverse_iterator<T> end)
{
  foo(end.base(), begin.base()); // Note: order of iteration reversed!
}

但请注意,现在迭代的顺序颠倒了:在我的示例中,调用foo(v.rbegin(), v.rend()) 在第一个化身中打印9 8 7 ... 1,现在它打印1 2 3 ... 9Example here.

再说一次,如果你能提供兼容的迭代器,你会做得更好。

【讨论】:

  • 我不太确定在创建这个函数签名模板后你会怎么做 void foo(T start, U end)
  • 是的,我正在努力扩展我的答案。给我一点时间:)
  • 感谢您的解决方案 mindriot。但我的主要问题是在模板函数中调用擦除函数。擦除只需要正向迭代器,而模板接受正向和反向迭代器。还有其他方法吗?
猜你喜欢
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2021-01-02
  • 1970-01-01
  • 2016-01-17
  • 1970-01-01
  • 2021-07-03
相关资源
最近更新 更多