在使用模板类时遇到链接器错误,我尝试按照此处的建议实现 copy-and-swap 习惯用法:
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;
}
我收到 Unresolved external 错误:
LNK2019:函数“public: class TemplateClass X & __thiscall TemplateClass X::operator=(class TemplateClass)”(. ..) 在 TestClass.obj 中
或者换句话说:
TestClass
中的东西来电 TemplateClass<HandledClass>::operator=
没有找到void swap( TemplateClass<HandledClass>, TemplateClass<HandledClass> )
.
所以我的问题是: 为什么运算符(operator)找不到交换方法?
看起来它没有针对模板参数进行编译。是否有可能让编译器也编译 friend void?
我可能会放弃 friend void
方法并定义一个类内交换方法加上一个类外交换方法加上 std 命名空间中的一个,但我不知道它是否会以这种方式工作,并且如果可能的话我想避免这种情况。
解决方案:
这完成了工作:
template< class t >
class TemplateClass
{
friend void swap( TemplateClass& first, TemplateClass& second )
{
// ...
}
};
请注意我如何也删除 < T > 出现的地方。
最佳答案
这是将非成员函数与模板融为一体时的常见问题。 friend
TemplateClass
内的声明不与你的swap
交 friend 模板,而是一个非模板化的自由函数 swap
这需要TemplateClass<T>
永远T
模板被实例化(即特化 TemplateClass<int>
将与未模板化的自由函数 void swap( TemplateClass<int>&,TemplateClass<int>& );
成为 friend )。
最好的解决方案是提供 swap
定义内联在类模板定义中,因为这将使编译器生成非模板化 swap
在需要时提供精确类型的函数。作为另一个积极的副作用,swap
函数只会在参数相关查找期间找到,因此它不会参与任何不涉及模板的重载解析。
其他替代方案正在与整体成为 friend swap
模板函数,或与 swap
的特定特化成为 friend 应用于相同的函数 T
模板已被实例化。第一个选项的代码很简单,但它授予对 swap
的所有特化的访问权限。模板,这可能会产生不好的副作用。与特定的人交 friend swap
特化解决了这个问题,但实现起来有点复杂(您需要向前声明类模板,然后声明 swap
模板,然后定义类模板,最后定义 swap
模板)。
有关此内容的更多信息,请参阅其他 answer ,其中更详细地解释了不同的选项和语法。
关于unresolved external
的具体错误信息,这是由于标识符查找的工作方式决定的。当您使用swap(*this,other);
时在成员函数内部,查找在类内部开始,并尝试找到合适的 swap
。它首先在类上下文中查找并找到friend
的声明。自由函数,因此查找不会继续向外并添加对该特定自由函数的依赖关系。它添加依赖项并等待链接器找到适当的符号。因为编译器从未考虑过模板化的 swap
在命名空间级别,它从未实际实例化它,但即使它实例化了该模板, operator=
内的依赖项成员函数是一个自由函数,没有那么特化。
关于c++ - Unresolved external 使用带有 copy-and-swap 的模板类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7331085/