使用正向和反向迭代器的 C++ 映射擦除
C++ map erase using forward and reverse iterators
我有一个这样的模板函数
template<typename T>
void foo(T start , T end)
{
while(start != end)
{
if(cond)
m.erase(start);
start++;
}
}
现在我必须将正向和反向迭代器作为类型名传递。两个单独的调用,其中一个是正向迭代器,一个是反向迭代器。我该怎么做呢 ?
首先,让我重申 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;
}
这里我将反向迭代器转换为正向迭代器。 This SO post gives you more details about that。但是仔细看那个post,有龙。我上面的例子只是输出数字,并没有修改底层容器。而且我不检查迭代器的有效性,也不做任何边界检查。对于您自己的情况,请确保测试所有边缘情况(迭代器处于或超出容器的 beginning/end;差一错误等)。
另请注意,在您的示例代码中,对 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 ... 9
。 Example here.
再说一次,如果您可以改用兼容的迭代器,您会过得更好。
我有一个这样的模板函数
template<typename T>
void foo(T start , T end)
{
while(start != end)
{
if(cond)
m.erase(start);
start++;
}
}
现在我必须将正向和反向迭代器作为类型名传递。两个单独的调用,其中一个是正向迭代器,一个是反向迭代器。我该怎么做呢 ?
首先,让我重申 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;
}
这里我将反向迭代器转换为正向迭代器。 This SO post gives you more details about that。但是仔细看那个post,有龙。我上面的例子只是输出数字,并没有修改底层容器。而且我不检查迭代器的有效性,也不做任何边界检查。对于您自己的情况,请确保测试所有边缘情况(迭代器处于或超出容器的 beginning/end;差一错误等)。
另请注意,在您的示例代码中,对 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 ... 9
。 Example here.
再说一次,如果您可以改用兼容的迭代器,您会过得更好。