模板参数阴影与朋友?

时间:2014-11-28 09:25:31

标签: c++ templates

在以下示例中,重载<< operator

#include <iostream>

template <typename T>
class MyClass {

    public:
        MyClass(T X, T Y):x(X), y(Y) {}

        template <typename U>
        friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);

    private:
        T x;
        T y;
};

template <typename T>
std::ostream& operator <<(std::ostream &os, const MyClass<T> &cl)
{
    os << cl.x << " " << cl.y;
    return os;
}

int main()
{
    MyClass<int> cl(1, 2);
    std::cout << cl << std::endl;
}

我搜索了其他问题,但我无法找到我需要的原因:

template <typename U>
friend std::ostream& operator <<(std::ostream &os, const MyClass<U> &cl);

U中的T代替typename?因为最后UT都是ints

1 个答案:

答案 0 :(得分:3)

您无法再次使用template <typename T>,因为在该行的其余部分,您不会知道您所指的两个T中的哪一个。它有点像这样,这也是一个错误:

void foo(int x) {
  int x = 4;
  cout << x;  // which x?
}

编译器不够聪明,无法弄清楚在这种情况下你总是希望两个T是相同的,就像上面foo函数中的错误不会消失一样如果您只在程序中调用了foo(4)

但是你在这里意识到的是,你根本不需要operator<<的模板参数!这是因为在这种情况下你确切地知道你想要使用什么类型,MyClass<T>。通常,当您知道所需的确切类型时,可以删除模板参数。这称为显式特化,通常看起来像这样:

template <>
friend std::ostream& operator<< <T>(std::ostream& os, const MyClass<T> &cl);

请注意空模板参数列表template <>,其中表示&#34;我不需要模板参数&#34;然后在函数名称之后的<T>表示,&#34;因为我希望模板参数类型完全是T&#34;,其中T已知MyClass模板的特定实例。但是这里不起作用,因为在C ++语言规范中只有一条规则,friend声明中不允许显式特化。 (我不确定这条规则背后的理由是什么,但它是一条规则。)

因为您无法重复使用标识符T,并且您无法明确专门化,所以剩下的唯一选择是使用一些其他标识符,例如U,用于模板参数。