我试图创建一个通用的函数,从一个std ::矢量去除重复。因为我不想为每个向量类型的功能,我想使这个模板函数,可以接受任何类型的载体。以下是我有:

//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);
}

我不断收到链接错误,但它编译罚款。任何想法,我做错了吗?

UPDATE:基于由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 ::向量,迭代器无法正常工作。所以我不得不去一个更通用的方法。此外,擦除compareIter时,在循环的下一次迭代产生一个指针异常。 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));
}
有帮助吗?

解决方案

短应答

定义在首部中的功能,优选地内的类定义。

龙答案

定义的.cpp里面的模板功能意味着它不会#included到任何翻译单元:它只会提供给它的定义翻译单元

因此RemoveVectorDuplicates必须在头被定义,因为这是编译器可以文本的替代的唯一途径模板参数,因此实例化模板,产生可用类。

有两种解决这种不便

<强>第一下,可以去除从在.cpp的#include "foo.h"并添加另外一个,在

#include "foo.cpp"

这可让您始终如一地组织你的文件,但不提供单独的编译通常的优势(更小的依赖,更快,罕见编译)。

上,你可以定义模板功能在.cpp,并明确实例化它,它会与被使用过的所有类型。

例如,这可以在在.cpp的端部去,使功能可用与ints:

template void Foo::RemoveVectorDuplicates(std::vector<int>*);

不过,这是假设你只使用模板来节省一些打字,而不是提供真正的通用性。

其他提示

在有一种替代方法是首先std::sort()载体中,然后使用预先存在的std::unique()函数来删除重复。排序需要O(n日志n)的时间,并删除重复的是只需要O(n)的所有重复出现在单个块中的时间后。您当前的 “全VS-所有” 比较算法需要O(N ^ 2)的时间。

您无法实现一个.cpp文件的模板功能。完整的实现必须是可见的地方中实例化。

只要定义在首部中的类定义中的功能。 这是实现模板函数通常的方式。

我会建议使用更“通用”的方式,而不是通过一个容器刚刚收到两个迭代器。

类似的东西remove_duplicates(它首先,它最后一个),它会返回一个迭代器,所以你可以调用像删除:v.erase(remove_duplicates(v.begin(), v.end()), v.end())

template <typename It>
It remove_duplicate(It first, It last)
{
  It current = first;
  while(current != last) {
    // Remove *current from [current+1,last)
    It next = current;
    ++next;
    last = std::remove(next, last, *current);
    current = next;
  }
  return last;
}

无关您的问题(这已被解释的),为什么这是一个静态函数,而不是在全球命名空间驻留?这将是有所C ++ - 。IER

我不认为代码编译....

vectorToUpdate.erase其中的std ::向量* vectorToUpdate ....没有任何人通知有一个*那里应该是A&?该代码是绝对不会被编译。如果你要使用一个指针到矢量您必须使用“ - >”而不是“”我知道,这其实是一个有点挑剔挑剔,但它指出,编译器甚至不关心你的代码...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top