模板友元 函数模板与类模板的声明都可以在非局部类或类模板中使用friend
说明符修饰(但只有函数模板可以定义在授予它友元权限的类或类模板中)。在这种情况下,所有特例化的模板都会成为一个友元,无论他是被隐式实例化、部分特例化或显式特例化。
1 2 3 4 5 6 7 class A { template <typename T> friend class B ; template <typename T> friend void f (T) {} };
友元声明不能用于部分特例化,但可以用于完全(显式)特例化:
1 2 3 4 5 6 7 template <class T > class A { }; template <class T > class A < T*> {}; template <> class A <int > {}; class X { template <class T > friend class A < T*>; friend class A <int >; };
当友元声明用于一个函数模板的完全特例化时,不能使用inline
关键字和默认参数:
1 2 3 4 5 6 template <class T> void f (int ) ;template <> void f<int >(int ); class X { friend void f<int >(int x = 1 ); };
模板友元运算符 模板友元的一个常见用途是声明一个非成员运算符重载其默认操作;例如,对用户定义的Foo<T>
声明operator<<(std::ostream&, const Foo<T>&)
。
该运算符可以定义在类内部,这样的效果是为每一个类型T
生成一个独立的非模板的operator<<
,并使这个非模板的operator<<
成为Foo<T>
的友元。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> template <typename T>class Foo { public : Foo (const T& val) : data (val) {} private : T data; friend std::ostream& operator <<(std::ostream& os, const Foo& obj) { return os << obj.data; } }; int main () { Foo<double > obj (1.23 ) ; std::cout << obj << '\n' ; }
或者函数模板必须在类之前进行模板声明,在这种情况下Foo<T>
之内的友元声明可使用类型T
进行完全特例化的operator<<
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> template <typename T>class Foo ; template <typename T> std::ostream& operator <<(std::ostream&, const Foo<T>&); template <typename T>class Foo { public : Foo (const T& val) : data (val) {} private : T data; friend std::ostream& operator << <> (std::ostream&, const Foo&); }; template <typename T> std::ostream& operator <<(std::ostream& os, const Foo<T>& obj) { return os << obj.data; } int main () { Foo<double > obj (1.23 ) ; std::cout << obj << '\n' ; }
内容来自:https://en.cppreference.com/w/cpp/language/friend