链接程序可以区分模板功能和非模板功能吗?

时间:2019-05-03 18:01:52

标签: c++ templates

我遇到了这样的规则:模板好友功能需要像这样向前声明:

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>朋友的朋友有什么不同?

编译器/链接器可以区分模板函数和非模板函数吗?

1 个答案:

答案 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); 模板并确保朋友声明引用该模板(或其专门化)的原因。