在以下示例中,重载<< 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
?因为最后U
和T
都是ints
。
答案 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
,用于模板参数。