可以链接器区分模板和非模板函数

Can linker differentiate between template and non-template functions?

本文关键字:函数 链接 器区      更新时间:2023-10-16

我遇到了需要这样声明的模板朋友函数的规则:

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>();
}

并阅读了它的解释,说明:

当编译器看到合适的类定义中的朋友上线时,就会发生障碍。那一刻,它尚不知道朋友的功能本身就是模板。它假设它们是非修辞...

...此假设导致编译器生成对非模板函数的调用,但是链接器将为您提供"未定义的外部"。错误,因为您从未真正定义那些非模板函数。

,但在我的理解中,r * r应该实例化

const Rational<int> operator* (const Rational<int>& lhs, const Rational<int>& rhs);

Rational<int>的朋友有何不同?

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

根据语言的规则([temp.fct]/2(:

非模板函数与函数模板无关(即,它从未被认为是专业化(,即使它具有相同的名称和类型与潜在生成的函数模板专业化。

使用第二个片段,当Rational<int>实例化时,朋友在其体内声明会引入 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*模板并确保朋友声明是指该模板(或其专业化(的原因。