你如何创建一个模板类执行操作的静态模板成员函数?
-
20-08-2019 - |
题
我试图创建一个通用的函数,从一个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里面的模板功能意味着它不会#include
d到任何翻译单元:它只会提供给它的定义翻译单元
因此RemoveVectorDuplicates
必须在头被定义,因为这是编译器可以文本的替代的唯一途径模板参数,因此实例化模板,产生可用类。
有两种解决这种不便
<强>第一下,可以去除从在.cpp的#include "foo.h"
并添加另外一个,在端的头:
#include "foo.cpp"
这可让您始终如一地组织你的文件,但不提供单独的编译通常的优势(更小的依赖,更快,罕见编译)。
二上,你可以定义模板功能在.cpp,并明确实例化它,它会与被使用过的所有类型。
例如,这可以在在.cpp的端部去,使功能可用与int
s:
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&?该代码是绝对不会被编译。如果你要使用一个指针到矢量您必须使用“ - >”而不是“”我知道,这其实是一个有点挑剔挑剔,但它指出,编译器甚至不关心你的代码...