下面是一个简短的例子,说明了我正在通过提供我自己的非成员朋友交换功能来创建和尝试制作可交换的更大的类。
#include <iostream>
#include <utility>
template<typename T>
class Wrapper {
friend void swap(Wrapper& a, Wrapper& b);
public:
Wrapper(T t) : value_(t) {}
const T& operator*() const { return value_; }
private:
T value_;
};
template<typename T>
void swap(Wrapper<T>& a, Wrapper<T>& b) {
using std::swap;
swap(a.value_, b.value_);
}
int main() {
Wrapper<int> w1{5}, w2{10};
std::cout << *w1 << " " << *w2 << std::endl;
swap(w1, w2);
std::cout << *w1 << " " << *w2 << std::endl;
}
尝试编译此小型测试程序会导致clang出现以下链接器错误(Apple XVM版本7.0.2,OS X El Capitan 10.11.3上的clang-700.1.81):
[~/Development/c++_test][16:30:57]$ clang++ --std=c++11 -o SwapTest SwapTest.cc
Undefined symbols for architecture x86_64:
"swap(Wrapper<int>&, Wrapper<int>&)", referenced from:
_main in SwapTest-a978ea.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
为什么我已经定义的Wrapper类的模板交换函数没有在main()中使用它而没有被适当地实例化?
答案 0 :(得分:4)
friend void swap(Wrapper& a, Wrapper& b);
声明一个非模板函数swap
恰好采用Wrapper<T>&
个参数。这与您的模板函数swap<T>
不匹配。
一个简单的解决方法是将朋友声明为模板函数。
template <typename U>
friend void swap(Wrapper<U>&a, Wrapper<U>& b);
缺点是你得到了比你想要的更多的东西:每个swap
实例化都是每个Wrapper<T>
的朋友,而不仅仅是正确的Wrapper<T>
类。
更正确的方法是在课程之前声明模板函数:
template <class T> class Wrapper;
template <class T>
void swap(Wrapper<T>&, Wrapper<T>&);
template <class T>
class Wrapper
{
friend void swap<>(Wrapper&, Wrapper&);
// ...
答案 1 :(得分:1)
只需将您的朋友声明更改为模板:
template<typename T>
class Wrapper {
template<typename U>
friend void swap(Wrapper<U>& a, Wrapper<U>& b);
...
gcc在尝试编译代码时会输出一个警告