在使用模板类时,我得到了一个链接器错误,我尝试实现这里建议的复制和交换成语:
What is the copy-and-swap idiom?
模板类(让我们称之为"TemplateClass“)部分地定义如下:
template< class T >
class TemplateClass
{
// ...
TemplateClass< T >& operator= ( TemplateClass< T > other );
friend void swap( TemplateClass< T >& first, TemplateClass< T >& second );
// ...
};我已经将实现放在一个单独的TemplateClass.cpp中,它包含在.h文件中。(编辑:如果所有内容都在.h文件中,我也会遇到同样的问题)
赋值操作符被定义为:
template< class T >
TemplateClass< T >& TemplateClass< T >::operator= ( TemplateClass< T > other )
{
// copy-and-swap idiom
swap( *this, other );
return *this;
}交换方法定义为:
template< class T >
void swap( TemplateClass< T >& first, TemplateClass< T >& second )
{
using namespace std;
swap( first.member1, second.member1 );
swap( first.member2, second.member2 );
// ...
}(别担心,我并没有把我的会员命名为"member1“等等)
我有一个类似的类,其定义方式相同,但不是模板类。那里一切都很好。但是,如果我有一个类TestClass,它有一个成员TemplateClass< HandledClass > member,并且我调用它的方法之一,如
void TestClass::setMember( TemplateClass< HandledClass > newObject )
{
member = newObject;
}我得到一个未解决的外部错误:
LNK2019:未解决的外部符号“__cdecl交换( TemplateClass &,类TemplateClass &)”(.)函数"public: class TemplateClass X& __thiscall TemplateClass X::operator=(class TemplateClass)“(.)在TestClass.obj中
或者换句话说:TestClass中的东西叫做TemplateClass<HandledClass>::operator=,它找不到void swap( TemplateClass<HandledClass>, TemplateClass<HandledClass> )。
所以我的问题是:为什么运算符找不到交换方法?
看起来它不是为模板参数编译的。是否有可能让编译器也编译好友空?
我可能会放弃friend void方法,定义类内交换方法,加上std命名空间中的类外交换方法,但是我不知道它是否会那样工作,如果可能的话,我想避免这种情况。
解决方案:
这做了以下工作:
template< class t >
class TemplateClass
{
friend void swap( TemplateClass& first, TemplateClass& second )
{
// ...
}
};请注意,我也必须删除事件。
发布于 2011-09-07 09:11:32
这是一个常见的问题,当朋友非会员函数与模板。friend声明在TemplateClass中并不是swap模板的朋友,而是一个非模板化的免费函数swap,它接受TemplateClass<T>,模板曾经被实例化过(也就是说,专门化TemplateClass<int>将成为一个没有模板化的免费函数void swap( TemplateClass<int>&,TemplateClass<int>& ); )。
最好的解决方案是在类模板定义中提供内联的swap定义,因为这将使编译器在需要时为精确的类型生成一个非模板的swap函数。另一个积极的副作用是,swap函数只能在参数依赖的查找过程中才能找到,因此它不会对任何不涉及模板的内容进行过载解析。
其他替代方法是将整个swap模板函数视为朋友,或者将swap函数的特定专门化应用于模板已被实例化的同一个T。第一个选项在代码中很简单,但它授予对swap模板的所有专门化的访问权限,这可能会产生不良的副作用。建立特定的swap专门化解决了这个问题,但是实现起来有点复杂(您需要转发声明类模板,然后是swap模板,然后定义类模板,最后定义swap模板)。
在另一个answer中,将更详细地解释不同的选项和语法。
至于unresolved external的特定错误消息,这是由于标识符查找是如何工作的。当在成员函数中使用swap(*this,other);时,查找将在类中开始,并试图找到适当的swap。它首先查找类上下文并找到friend空闲函数的声明,因此查找不会继续向外扩展,并向该特定的空闲函数添加依赖项。它添加依赖项,并等待链接器找到适当的符号。因为编译器从来没有在名称空间级别考虑过模板化的swap,所以它从未实际实例化它,但是即使它实例化了该模板,operator=成员函数中的依赖项是在一个空闲函数上,而不是在专门化上。
发布于 2011-09-07 09:01:26
您应该将类模板的声明放入头文件,或者如果您事先知道将对该类模板进行实例化的所有类型,则在头文件处提供显式实例化:
template< class T >
class TemplateClass
{
// ...
TemplateClass< T >& operator= ( TemplateClass< T > other );
friend void swap( TemplateClass< T >& first, TemplateClass< T >& second );
// ...
};
template class TemplateClass<FirstType>;
template class TemplateClass<SecondType>;
// ...
// and the same for swap function
template void swap<FirstType>( TemplateClass<FirstType>& first, TemplateClass<FirstType>& second );
template void swap<SecondType>( TemplateClass<SecondType>& first, TemplateClass<SecondType>& second );这很乏味,但有时这是最好的选择。
关于交换没有链接的原因:您使用非模板函数交换来声明友谊,这不会exist.Try如下:
template< class T >
class TemplateClass
{
// ...
TemplateClass< T >& operator= ( TemplateClass< T > other );
template < class U > friend void swap( TemplateClass< U >& first, TemplateClass< U >& second );
// ...
};如果您想成为一个纯粹主义者,并且只与“您的”swap (具有相同模板参数的swap)做朋友,则需要额外的努力。
https://stackoverflow.com/questions/7331085
复制相似问题