我正在尝试创建一个从 std::vector 中删除重复项的通用函数。因为我不想为每个向量类型创建一个函数,所以我想让它成为一个模板函数,可以接受任何类型的向量。这是我所拥有的:
//foo.h
Class Foo {
template<typename T>
static void RemoveVectorDuplicates(std::vector<T>& vectorToUpdate);
};
//foo.cpp
template<typename T>
void Foo::RemoveVectorDuplicates(std::vector<T>& vectorToUpdate) {
for(typename T::iterator sourceIter = vectorToUpdate.begin(); (sourceIter != vectorToUpdate.end() - 1); sourceIter++) {
for(typename T::iterator compareIter = (vectorToUpdate.begin() + 1); compareIter != vectorToUpdate.end(); compareIter++) {
if(sourceIter == compareIter) {
vectorToUpdate.erase(compareIter);
}
}
}
}
//SomeOtherClass.cpp
#include "foo.h"
...
void SomeOtherClass::SomeFunction(void) {
std::vector<int> myVector;
//fill vector with values
Foo::RemoveVectorDuplicates(myVector);
}
我不断收到链接器错误,但它编译得很好。关于我做错了什么的任何想法?
更新:根据 Iraimbilanja 给出的答案,我去重写了代码。但是,以防万一有人想让工作代码执行 RemoveDuplicates 函数,这里是:
//foo.h
Class Foo {
template<typename T>
static void RemoveVectorDuplicates(T& vectorToUpdate){
for(typename T::iterator sourceIter = vectorToUpdate.begin(); sourceIter != vectorToUpdate.end(); sourceIter++) {
for(typename T::iterator compareIter = (sourceIter + 1); compareIter != vectorToUpdate.end(); compareIter++) {
if(*sourceIter == *compareIter) {
compareIter = vectorToUpdate.erase(compareIter);
}
}
}
};
事实证明,如果我在签名中指定 std::vector,迭代器将无法正常工作。所以我不得不采用更通用的方法。此外,当擦除 compareIter 时,循环的下一次迭代会产生指针异常。擦除后 compareIter 的后减量可以解决该问题。我还修复了迭代器比较和第二个循环中 compareIter 初始化中的错误。
更新 2:
我看到这个问题又得到了赞成票,所以我想用一个更好的算法来更新它,这个算法使用了一些 C++14 的优点。我的前一个只有在向量中存储的类型实现 operator== 并且它需要一堆副本和不必要的比较时才有效。而且,事后看来,没有必要让它成为一个类的成员。这种新算法允许自定义比较谓词,在发现重复项时缩小比较空间,并显着减少副本数量。名称已更改为erase_duplicates
更好地符合 STL 算法命名约定。
template<typename T>
static void erase_duplicates(T& containerToUpdate)
{
erase_duplicates(containerToUpdate, nullptr);
}
template<typename T>
static void erase_duplicates(T& containerToUpdate,
std::function<bool (typename T::value_type const&, typename T::value_type const&)> pred)
{
auto lastNonDuplicateIter = begin(containerToUpdate);
auto firstDuplicateIter = end(containerToUpdate);
while (lastNonDuplicateIter != firstDuplicateIter) {
firstDuplicateIter = std::remove_if(lastNonDuplicateIter + 1, firstDuplicateIter,
[&lastNonDuplicateIter, &pred](auto const& compareItem){
if (pred != nullptr) {
return pred(*lastNonDuplicateIter, compareItem);
}
else {
return *lastNonDuplicateIter == compareItem;
}
});
++lastNonDuplicateIter;
}
containerToUpdate.erase(firstDuplicateIter, end(containerToUpdate));
}