转自:http://www.cppblog.com/zerolee/archive/2010/11/03/132344.html
类模板的模板友元函数定义有2种方式:
1. 将友元模板函数直接定义在类模板中。这种方式比较简单直接。
2. 将友元模板函数声明在类模板中,定义在类模板之外。这种方式的写法,如果不小心,通常会出现编译没问题,链接时无法解析的错误。
以下是一个简单的正确的例子:
1 #include <iostream>
2 #include <vector>
3
4 template <typename T>
5 class Number;
6
7 template <typename T>
8 void print(const Number<T>& n);
9
10 template <typename T>
11 std::ostream& operator << (std::ostream& os, const Number<T>& n);
12
13 template <typename T>
14 std::istream& operator>>(std::istream& is, Number<T>& n);
15
16 template <typename T, typename T2>
17 void printVector(const std::vector<T2>& vt, const Number<T>& n);
18
19 template <typename T>
20 class Number {
21 public:
22 Number(T v)
23 : val(v) {}
24 ~Number() {}
25
26 private:
27 T val;
28 public:
29 friend void print<T> (const Number<T>& n);
30 friend std::ostream& operator << <T>(std::ostream& os, const Number<T>& n);
31 friend std::istream& operator>> <T>(std::istream& is, Number<T>& n);
32
33 friend Number<T>& operator += (Number<T>& a, const Number<T>& b)
34 {
35 a.val += b.val;
36 return a;
37 }
38 template <typename T2>
39 friend void printVector<T>(const std::vector<T2>& vt, const Number<T>& n);
40 template <typename T2>
41 void memFunc(const std::vector<T2>& vt, const Number<T>& n);
42 };
43
44 template <typename T>
45 std::ostream& operator <<(std::ostream& os, const Number<T>& n)
46 {
47 os << n.val << std::endl;
48 return os;
49 }
50
51 template <typename T>
52 std::istream& operator >>(std::istream& is, Number<T>& n)
53 {
54 is >> n.val;
55 return is;
56 }
57
58 template <typename T>
59 void print<T> (const Number<T>& n)
60 {
61 std::cout << n;
62 }
63
64 template <typename T, typename T2>
65 void printVector(const std::vector<T2>& vt, const Number<T>& n)
66 {
67 for (unsigned int i = 0; i < vt.size(); i++)
68 std::cout << vt.at(i) << " ";
69 std::cout << "=> " << n;
70 }
71
72 template <typename T>
73 template <typename T2>
74 void Number<T>::memFunc(const std::vector<T2>& vt, const Number<T>& n)
75 {
76 for (unsigned int i = 0; i < vt.size(); i++)
77 std::cout << vt.at(i) << " ";
78 std::cout << "=> " << n;
79 }
80
2 #include <vector>
3
4 template <typename T>
5 class Number;
6
7 template <typename T>
8 void print(const Number<T>& n);
9
10 template <typename T>
11 std::ostream& operator << (std::ostream& os, const Number<T>& n);
12
13 template <typename T>
14 std::istream& operator>>(std::istream& is, Number<T>& n);
15
16 template <typename T, typename T2>
17 void printVector(const std::vector<T2>& vt, const Number<T>& n);
18
19 template <typename T>
20 class Number {
21 public:
22 Number(T v)
23 : val(v) {}
24 ~Number() {}
25
26 private:
27 T val;
28 public:
29 friend void print<T> (const Number<T>& n);
30 friend std::ostream& operator << <T>(std::ostream& os, const Number<T>& n);
31 friend std::istream& operator>> <T>(std::istream& is, Number<T>& n);
32
33 friend Number<T>& operator += (Number<T>& a, const Number<T>& b)
34 {
35 a.val += b.val;
36 return a;
37 }
38 template <typename T2>
39 friend void printVector<T>(const std::vector<T2>& vt, const Number<T>& n);
40 template <typename T2>
41 void memFunc(const std::vector<T2>& vt, const Number<T>& n);
42 };
43
44 template <typename T>
45 std::ostream& operator <<(std::ostream& os, const Number<T>& n)
46 {
47 os << n.val << std::endl;
48 return os;
49 }
50
51 template <typename T>
52 std::istream& operator >>(std::istream& is, Number<T>& n)
53 {
54 is >> n.val;
55 return is;
56 }
57
58 template <typename T>
59 void print<T> (const Number<T>& n)
60 {
61 std::cout << n;
62 }
63
64 template <typename T, typename T2>
65 void printVector(const std::vector<T2>& vt, const Number<T>& n)
66 {
67 for (unsigned int i = 0; i < vt.size(); i++)
68 std::cout << vt.at(i) << " ";
69 std::cout << "=> " << n;
70 }
71
72 template <typename T>
73 template <typename T2>
74 void Number<T>::memFunc(const std::vector<T2>& vt, const Number<T>& n)
75 {
76 for (unsigned int i = 0; i < vt.size(); i++)
77 std::cout << vt.at(i) << " ";
78 std::cout << "=> " << n;
79 }
80
1) 以上代码中,operator +=被定义在类模板内部。其他3个函数先被声明(需提前声明类模板,如果模板函数的参数中含有类模板),然后在类模板中被声明为友元函数, 之后被定义在类模板体之外。
2) 请注意当模板函数被声明为类模板的友元时,在函数名之后必须紧跟模板实参表,用来代表该友元声明指向函数模板的实例。否则友元函数会被解释为一个非模板函数,链接时无法解析。
3) 友元模板函数的模板参数类型,并不一定要求是类模板的参数类型,也可以另外声明。