C++模板编程


637 浏览 5 years, 4 months

3.3 类模板的friend函数模板

版权声明: 转载请注明出处 http://www.codingsoho.com/

类模板的friend函数模板

如果需要在类模板中重载运算符,函数模板会非常有用。例如,为了能把一个网格输出到一个流中,需要为Grid类模板重载插入运算符(operator<<) 。

根据前面的讨论,不能将operator<<设置为Grid类的成员:这个运算符必须是一个独立的函数模板。这个定义应该直接放在Grid.h中,如下所示:

template <typename T>
ostream& operator<<(ostream& ostr, const Grid<T>& grid)
{
    for (size_t i = 0; i < grid.mHeight; i++) {
        for (size_t j = 0; j < grid.mWidth; j++) {
            // add a tab between each element of a row
            ostr << grid.mCells[j][i] << "\t"; 
        }
        ostr << std::endl; // add a newline between each row
    }
    return ostr;
}

这个函数模板可用于任何Grid,只要网格的元素支持插入运算符即可。唯一存在的问题是operator<<访问了Grid类的protected成员。因此,operator<<必须是Grid类的friend。然而,Grid类和operator<<两者都是模板。实际上需要以下效果:operator<<对每一个特定类型T的实例化都是Grid模板对这个类型实例化的friend。这个语法如下所示:

// Forward declare Grid template.
template <typename T> class Grid;

// Prototype for templatized operator<<. 
template<typename T>
ostream& operator<<(ostream& ostr, const Grid<T>& grid);

template <typename T>
class Grid
{
public:
    friend ostream& operator<< <T>(ostream& ostr, const Grid<T>& grid);
};

friend声明比较棘手:这个语法表明,对于这个模板对类型T的实例,operator<<对类型T的实例是这个模板实例的friend。换句话说,类实例和函数实例之间存在一对一的friend映射关系。特别要注意operator<<中显式的模板规范<T>(<<后面的空格是可选的,但为了便于阅读,这里应该添加空格)。这个语法告诉编译器operator<<本身也是一个模板。