【问题标题】:Can linker differentiate between template and non-template functions?链接器可以区分模板函数和非模板函数吗?
【发布时间】:2019-05-03 18:01:52
【问题描述】:

我发现了模板友元函数需要像这样前向声明的规则:

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&lt;int&gt;的朋友有什么不同?

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

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

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

    非模板函数与函数模板无关(即,它从不被视为特化),即使它与可能生成的函数模板特化具有相同的名称和类型。

    使用第二个 sn-p,当 Rational&lt;int&gt; 被实例化时,其主体中的朋友声明引入了一个非模板函数的声明:

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

    【讨论】:

      猜你喜欢
      • 2010-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多