模板类声明也可以有友元, 模板的友元分为3类:
1.非模板友元
2.约束模板友元, 即友元的类型取决于类被实例化时的类型
3.非约束模板友元, 即友元的所有具体化都是类的每一个具体化的友元.
在模板类中将一个常规函数声明为友元:
template
class HasFriend
{
public:
friend void counts();
};
上述声明使counts()函数称为模板所有实例化的友元. 例如: 它将是类HasFriend
counts()函数不是通过对象调用的(它是友元, 不是成员函数)
假设要为友元函数提供模板类参数, 看如下的声明:
friend void report(HasFriend &);
这个声明是错误的, 因为不存在HasFriend这样的对象, 而只有特定的具体化如:HasFriend
template
class HasFriend
{
friend void report(HasFriend &);
};
注意report()本身并不是模板函数, 而只是使用了一个模板作为参数
来看一个完整的例子:
// 模板类的非模板友元函数例子
// frnd2tmp.cpp
#include
using std::cout;
using std::endl;
template
class HasFriend
{
private:
T item;
// 静态成员, 意味着每个类的特定具体化都将有自己的静态成员.
static int ct;
public:
HasFriend(const T & i): item(i) {ct++;}
~HasFriend() {ct--;}
friend void counts();
friend void reports(HasFriend &);
};
template
int HasFriend::ct = 0;
// 非模板友元函数, 所有HasFriend都有该函数
void counts()
{
cout << "int count: " << HasFriend::ct << "; ";
cout << "double count: " << HasFriend::ct << endl;
}
// 非模板友元函数, 对应于HasFriend class
void reports(HasFriend & hf)
{
cout << "HasFriend: " << hf.item << endl;
}
// 非模板友元函数, 对应于HasFriend class
void reports(HasFriend & hf)
{
cout << "HasFriend: " << hf.item << endl;
}
int main()
{
cout << "No objects declared: ";
counts();
HasFriend hfi1(10);
cout << "After hfi1 declared: ";
counts();
HasFriend hfi2(20);
cout << "After hfi2 declared: ";
counts();
HasFriend hfi3(10.1);
cout << "After hfi3 declared: ";
counts();
reports(hfi1);
reports(hfi2);
reports(hfi3);
return 0;
}
程序运行结果为:
需要注意的地方都写注释了
在上面这个示例基础上加以修改, 要使类的每一个具体化都获得与友元匹配的具体化, 需要以下三步:
1.在类定义的前面声明每个模板函数:
template void counts();
template void report(T &);
2.在函数中再次将模板声明为友元. 这些语句根据类模板参数的类型声明具体化:
template
class HasFriendT
{
...
friend void counts();
friend void report<>(HasFriendT &);
};
声明中的<>指出这是模板具体化, 对于report(), <>可以为空, 因为可以从函数参数推断出如下模板类型参数:
HasFriendT
然而也可以使用:
friend void report>(HasFriendT &);
但counts()函数没有参数, 因此必须使用模板参数语法来指明其具体化.
3.为友元提供模板定义.
下面看一个完整的例子:
// 模板类的约束模板友元函数
// tmp2tmp.cpp
#include
using std::cout;
using std::endl;
// 在类定义前面要声明每个模板函数原型
template void counts();
template void report(T &);
// 模板类
template
class HasFriendT
{
private:
TT item;
// 静态成员, 每个类的具体化都会有自己的静态成员
static int ct;
public:
HasFriendT(const TT & i):item(i){ct++;}
~HasFriendT() {ct--;}
friend void counts();
friend void report<>(HasFriendT &);
};
template
// 记得这里一定要写成HasFriendT, 不能只写HasFriendT, 因为不存在HasFriendT这个类
int HasFriendT::ct = 0;
// 模板友元函数定义
template
void counts()
{
cout << "template size: " << sizeof(HasFriendT) << ";";
cout << "template counts() : " << HasFriendT::ct << endl;
}
template
void report(T & hf)
{
cout << hf.item << endl;
}
int main()
{
counts();
HasFriendT hf1(10);
HasFriendT hf2(20);
HasFriendT hf3(10.1);
report(hf1);
report(hf2);
report(hf3);
cout << "counts output: " << endl;
counts();
cout << "counts() output: " <();
return 0;
}
程序运行结果为:
约束模板友元函数是在类外面声明的模板的具体化, int类具体化获得int函数具体化, 以此类推. 通过在类内部声明模板, 可以创建非约束友元函数, 即每个函数具体化都是每个类具体化的友元. 对于非约束友元, 友元模板类型参数和模板类类型参数是不同的:
template
class ManyFriend
{
template friend void show2(C &, D &);
}
来看一个demo:
// 非约束模板友元
// manyfrnd.cpp
#include
using std::cout;
using std::endl;
template
class ManyFriend
{
private:
T item;
public:
ManyFriend(const T & i): item(i){}
// 非约束模板友元
template friend void show2(C &, D &);
};
template void show2(C & c, D & d)
{
cout << c.item << ", " << d.item << endl;
}
int main()
{
ManyFriend hf1(10);
ManyFriend hf2(20);
ManyFriend hf3(10.1);
cout << "hf1, hf2: ";
show2(hf1, hf2);
cout << "hf3, hf2: ";
show2(hf3, hf2);
return 0;
}
程序运行结果为:
可以使用typedef为模板具体化指定别名:
格式如下:
template using arrtype = std::array;
这将arrtype定义为一个模板别名, 可使用其来指定类型例如:
// 实际为std::array这种类型
arrtype gallons;
// 实际为std::array这种类型
arrtype days;
// 实际为std::array这种类型
arrtype months;
C++允许将语法using = 用于非模板, 用于模板时, 这种语法与常规typedef等价