将函数模板设为友元



用类模板设计时,有时需要在类定义中声明友元函数,比如重载输出操作符<<,而当友元函数是模板函数时,则需要满足一些声明和定义的规则。

如,当我编写一个顺序表类模板时,加入了重载<<的友元模板如下:

template <typename T> class SeqList

{
friend std::ostream& operator << (std::ostream& os,const SeqList<T>& slist);
//……
};

此时在main.cpp文件中定义operator << 如下
template <typename T>
ostream& operator << (ostream& os,const SeqList<T>& slist)

{
return slist.printList(os);
}

编译通过,但链接报错!error LNK2019: 无法解析的外部符号 ……

由于我水平有限,至今仍不能读懂链接错误,唯有求助网络及红宝书(C++ Primer)了。


以下来自C++ Primer:
在类模板中可以出现三种友元声明……
(1)普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数。
(2)类模板或函数模板的友元声明,授予对友元所有实例的访问权。
(3)只授予对类模板或函数模板的特定实例的访问权的友元声明。

想要限制对特定实例化的友元关系时,必须在可以用友元声明之前声明类或函数


读完后我的理解是
当声明的友元函数不是模板函数,或者该函数是与类模板有不一样的typename的函数模板时,在类中声明该函数友元相当于声明了该函数。

但显然,上述遇到的问题属于第(3)种,而按书中所说,在声明友元std::ostream& operator <<时,应当先在类SeqList<T>定义之前声明该函数(而这又意味着在声明该函数前还需先声明类SeqList——template <typename T> class SeqList;)

在CSDN论坛中又搜到另一种方法。


上述问题的解决办法可总结如下两种:
1、声明友元前先声明函数模板,原方案变为
template <typename T> class SeqList;//声明类

template <typename T> //声明重载函数模板
std::ostream& operator << (std::ostream&,const SeqList<T>&);

template <typename T> class SeqList{
//声明为友元

friend std::ostream& operator << <T>(std::ostream& os,const SeqList<T>& slist);
//红色标记处不可省略:表明这是函数模板
}
//定义函数模板时不变
template <typename T>
ostream& operator << (ostream& os,const SeqList<T>& slist){
return slist.printList(os);
}

2、无需在类定义前声明函数模板,而是将友元函数的定义直接写在类的定义中
template <typename T> class SeqList{
//……

//直接定义函数
friend std::ostream& operator << <T>(std::ostream& os,const SeqList<T>& slist){
return slist.printList(os);//???此处省略<T>,VS2008不报错,奇怪???
}
}

测试用例2:

(1)声明友元前先声明函数模板,声明函数模板前先声明类模板

#include "stdafx.h"
#include <iostream>
using namespace std;


template <class T>
class Test;
template <class T>
ostream& operator <<(ostream& out,const Test <T> & obj);

template <class T>
class Test
{
private:
int num;
public:
Test(int n=0){num=n;}
Test(const Test <T> & copy){num=copy.num;}
friend ostream& operator<< <>(ostream& out,const Test <T> & obj);

};
template <class T>
ostream& operator<<(ostream& out,const Test <T> & obj)
{
out<<obj.num;
return out;
}

int main()
{
Test <int> t(2);
cout <<t <<endl; //输出2
return 0;
}
(2)将友元定义直接写在类定义中

#include "stdafx.h"
#include <iostream>
using namespace std;

template <class T>
class Test
{
private:
int num;
public:
Test(int n=0){num=n;}
Test(const Test <T> & copy){num=copy.num;}
friend ostream& operator<<(ostream& out,const Test <T> & obj)
{
out<<obj.num;
return out;
}
};

int main()
{
Test <int> t(2);
cout <<t <<endl; //输出2
return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值