Я пытаюсь создать универсальную функцию, которая удаляет дубликаты из 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);
}
Я получаю ошибку компоновщика, но он компилируется нормально. Есть идеи, что я делаю не так?
ОБНОВЛЕНИЕ: Основываясь на ответе Ираимбиланья, я пошел и переписал код. Однако на тот случай, если кто-то хочет, чтобы рабочий код выполнял функцию 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 во втором цикле.
ОБНОВЛЕНИЕ 2:
Я видел, что этот вопрос получил еще один голос, поэтому решил обновить его с помощью лучшего алгоритма, использующего некоторые достоинства C ++ 14. Мой предыдущий работал только в том случае, если тип, сохраненный в векторе, реализовал оператор == и требовал кучу копий и ненужных сравнений. И, оглядываясь назад, нет необходимости делать его членом класса. Этот новый алгоритм учитывает пользовательский предикат сравнения, сокращает пространство сравнения при обнаружении дубликатов и делает значительно меньшее количество копий. Имя было изменено на 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));
}