我先前问过this question。我对std :: set很感兴趣,但我有另一个令人困惑的场景。
即,以下代码是合法的,可移植的c ++ for T = std :: vector和T = std :: set:
template <typename T>
void remove_elements(T& collection, int removal_value)
{
typename T::iterator new_end =
std::remove(collection.begin(), collection.end(), removal_value);
collection.erase(new_end, collection.end());
}
根据SGI引用,set :: iterator和set :: const_iterator是相同的,所以我不知道这是否合法。但是,我似乎找不到另一种方法来获得我需要工作的操作,无论类型如何。我可以使用模板专业化,但是最好不要专注于第一名。
答案 0 :(得分:2)
erase-remove idiom仅适用于序列容器。对于标准的关联容器,它不起作用,解决方案也不那么简单。
两种方法:
remove_copy_if
复制所有内容
价值成另一个临时
容器然后交换内容
与那些原始容器的
暂时的。 [请将我的answer提交给相关的问题解答] 有关详细信息,请参阅此问题:remove_if equivalent for std::map
另外,请参阅第9项。选择Scott Meyers的Effective STL中的擦除选项。
答案 1 :(得分:1)
不,它不适用于std::set
,因为std::remove()
的一个要求是迭代器是一个可变迭代器,而std::set
的迭代器是不可变的。
遗憾的是,我没有任何好的选择。您可以做的一件事是使用std::find()
来查找元素出现的迭代器,然后在迭代器上使用.erase()
方法(std::vector
和{ {1}})删除它;并继续这样做,直到没有更多这样的元素。但这可能是非常低效的,O(n ^ 2)而不是O(n)。
答案 2 :(得分:0)
我认为“正确”的答案是remove_elements
重载std::set
。由于set是有序的并且不包含重复项,因此删除等于removed_value的元素要比向量或通用序列简单得多。你真的不想对所有事情使用相同的算法,即使你可以:
template <typename T>
void remove_elements(T& collection, const typename T::value_type& removal_value)
{
typename T::iterator new_end =
std::remove(collection.begin(), collection.end(), removal_value);
collection.erase(new_end, collection.end());
}
template<typename T>
void remove_elements(std::set<T>& collection, const T& removal_value)
{
collection.erase(removal_value);
}
我有点担心这些是否含糊不清,但在最明显的用例中,它们对我来说似乎没问题。
如果你有其他唯一排序关联容器比std :: set担心,这有点痛苦。你正在进入std :: swap领域,你实现的每个类都必须提供remove_elements的重载。但是因为set是你要问的唯一一个类,我认为这是你实际使用的唯一棘手的情况,至少目前是这样。如有必要,您可以使用特征根据容器的属性选择正确的算法版本。