模板类的友元函数
非模板友元函数
模板类的非模板友元函数是说该模板类的友元函数只是一个普通函数,并且该函数是非模板函数或该函数不视为模板函数。这里包含了两种情况,下面分别就两个例子进行说明。
• 函数是非模板函数
这一类友元函数特点是不带有参数列表,例如:friend void Fn()。这类友元函数通常可以用于全局对象的访问。
#include <iostream> using namespace std; template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: friend void PrintGlobalNumber(); }; MyNumber<int> g_GlobalNumber(1); void PrintGlobalNumber() { cout << "Global Number is : " << g_GlobalNumber.m_number << endl; } int main() { PrintGlobalNumber(); return 1; }
• 函数不视为模板函数
这类友元函数通常带有参数,并且参数中含有模板类定义的类型变量,例如:friend void Fn(MyClass<T> &n)。由于我们不将该函数视为模板函数,因此对模板类的每个实例化版本都需要提供该函数的一个重载版本。
需要注意,这种用法g++编译器将会给出警告:warning: friend declaration ‘xxxx’ declares a non-template function [-Wnon-template-friend]。关闭该警告方法是加入选项-Wno-non-template-friend,例如:g++ -Wno-non-template-friend -o test test.cpp。
#include <iostream> using namespace std; template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: friend void PrintNumber(MyNumber<T> &number); }; void PrintNumber(MyNumber<int> &number) { cout << "Int Number is : " << number.m_number << endl; } void PrintNumber(MyNumber<float> &number) { cout << "Float Number is : " << number.m_number << endl; } int main() { MyNumber<int> n0(1 ); MyNumber<float> n1(2.0f); PrintNumber(n0); PrintNumber(n1); return 1; }
模板类的约束模板友元函数
如果使用上面第二种方法来定义友元函数,那么局限性非常大:每当增加一个模板类的具体实例,就要相对应提供友元函数的一个重载版本。最好的办法就是应该将友元函数使用模板来实现。这里所谓的约束模板友元,指的是模板友元函数实例化取决于模板类被实例化时的类型。
• T(function) = T(class)
这种写法是保持模板友元函数的参数类型和模板类的参数类型一致。可以将友元函数的声明和定义分开,也可以直接在模板类内部直接定义友元函数。需要注意两种实现写法上的不同。
▶ 友元函数声明和定义分开
#include <iostream> using namespace std; // declare template function, T(function) = T(class) template <class T> class MyNumber; template <class T> void PrintNumber(MyNumber<T> &number); template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: // declare friend function friend void PrintNumber<T>(MyNumber<T> &number);
}; // function definition template <class T> void PrintNumber(MyNumber<T> &number) { cout << "The Number is : " << number.m_number << endl; } int main() { MyNumber<int> n0(1 ); MyNumber<float> n1(2.0f); PrintNumber(n0); PrintNumber(n1); return 1; }
▶ 友元函数直接定义在模板类内部
#include <iostream> using namespace std; template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: friend void PrintNumber(MyNumber<T> &number) { cout << "The Number is : " << number.m_number << endl; } }; int main() { MyNumber<int> n0(1); MyNumber<float> n1(2.0f); PrintNumber(n0); PrintNumber(n1); return 1; }
• T(function) = class<T>
这种写法是让模板友元函数的参数类型和模板类类型一致。
#include <iostream> using namespace std; // declare template function, T(function) = class<T> template <class T> void PrintNumber(T &number); template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: // declare friend function friend void PrintNumber<MyNumber<T> >(MyNumber<T> &number); }; // function definition template <class T> void PrintNumber(T &number) { cout << "The Number is : " << number.m_number << endl; } int main() { MyNumber<int> n0(1 ); MyNumber<float> n1(2.0f); PrintNumber(n0); PrintNumber(n1); return 1; }
模板类的非约束模板友元函数
这里所谓的约束模板友元,指的是友元函数的所有实例化版本都是模板类的每一个实例化版本的友元。
• T(function) = T(class)
这种写法是保持模板友元函数的参数类型和模板类的参数类型一致。
#include <iostream> using namespace std; template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: template <class D> friend void PrintNumber(MyNumber<D> &number); }; template <class T> void PrintNumber(MyNumber<T> &number) { cout << "The Number is : " << number.m_number << endl; } int main() { MyNumber<int> n0(1); MyNumber<float> n1(2.0f); PrintNumber(n0); PrintNumber(n1); return 1; }
• T(function) = class<T>
这种写法是让模板友元函数的参数类型和模板类类型一致。
#include <iostream> using namespace std; template <class T> class MyNumber { private: T m_number; public: MyNumber(T number) : m_number(number) {} ~MyNumber() {} public: template <class D> friend void PrintNumber(D &number); }; template <class T> void PrintNumber(T &number) { cout << "The Number is : " << number.m_number << endl; } int main() { MyNumber<int> n0(1); MyNumber<float> n1(2.0f); PrintNumber(n0); PrintNumber(n1); return 1; }