友元函数的技巧
友元函数大家习惯将声明和定义分开写,如
#include <iostream>
namespace Me
{
struct Int {
int i = 0;
friend std::ostream& operator<<(std::ostream& os, const Int& i);
};
std::ostream& operator<<(std::ostream& os, const Int& i)
{
os << i << " ";
return os;
}
} // namespace Me
然而,将友元函数直接写在类的定义内是更好的写法
namespace He
{
struct Int {
int i = 0;
friend std::ostream& operator<<(std::ostream& os, const Int& i)
{
os << i << " ";
return os;
}
};
} // namespace He
这时友元函数仅能通过ADL查找到,如
struct Bar {
};
void foo()
{
Me::Int i;
std::cout << i << std::endl;
He::Int j;
std::cout << j << std::endl;
Me::operator<<(std::cout, i);
He::operator<<(std::cout, j); //error
Bar bar;
std::cout << bar << std::endl;
}
int main() { foo(); }
这时 He::operator«(std::cout, j)将失败,因为在He namespace找不到 operator«,而只能通过ADL如std::cout«j。 好处是在运算符重载决议出错时,将不考虑将He::operator«纳入报错的重载集。比如对于bar的输出std::cout « bar « std::endl,错误信息里会包含Me::operator«,而不会包含 He::operator«。试试新的友元函数的定义方式吧,表达力更强,也更易排错。
Posted 2019-10-11