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