我遇到了这样的规则:模板好友功能需要像这样向前声明:
template<typename T>
class Rational;
template<typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs);
template<typename T>
class Rational {
public:
friend
const Rational operator *<> (const Rational& lhs, const Rational& rhs);
};
template<typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs)
{
return Rational<T>();
}
int main(void)
{
Rational<int> r;
r = r * r;
return 0;
}
不仅仅是写作
template<typename T>
class Rational {
public:
friend
const Rational operator * (const Rational& lhs, const Rational& rhs);
};
template<typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs)
{
return Rational<T>();
}
并阅读explanation并指出:
当编译器在类定义中正确地看到了朋友行时,就会出现这种障碍。那时还不知道朋友功能本身就是模板;假设它们是非模板...
...这种假设会使编译器生成对非模板函数的调用,但是链接器会给您一个“未定义的外部”错误,因为您从未实际定义那些非模板函数。
但是据我了解,r * r
应该实例化
const Rational<int> operator* (const Rational<int>& lhs, const Rational<int>& rhs);
与成为Rational<int>
朋友的朋友有什么不同?
编译器/链接器可以区分模板函数和非模板函数吗?
答案 0 :(得分:1)
根据语言规则([temp.fct] / 2):
非模板功能与功能模板无关(即永远不会被视为专业化),即使其名称和类型与可能生成的功能模板专业化相同。
在第二个代码段中,当实例化Rational<int>
时,其主体中的friend声明引入了 non-template 函数的声明:
const Rational<int> operator*(const Rational<int>&, const Rational<int>&);
程序中不存在此功能的定义,事实上,operator*
模板甚至都没有实例化,因为它失去了对非模板operator*
的重载分辨率。因此,从链接器的角度来看,根本没有operator*
。
但是即使operator*
模板已经实例化,也会导致编译器发出
const Rational<int> operator*<int>(const Rational<int>&, const Rational<int>&);
这是与非模板operator*
截然不同的功能,非模板r * r
实际上是r * r
所要求的。如果链接器允许r * r
调用模板特化,则将导致operator*
调用与标准要求调用的函数不同的函数。 (但是,从技术上讲,链接器没有义务发出错误消息,因为这是“无需诊断”错误。)
这就是为什么必须事先声明const headers = new Headers();
headers.set('Access-Control-Allow-Origin', '*');
const init = {
method: HTTP_METHODS.POST,
headers
};
const response await fetch(URL, init);
模板并确保朋友声明引用该模板(或其专门化)的原因。