c++ - 链接器可以区分模板函数和非模板函数吗?

标签 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因为它指出:

The snag happens when the compiler sees the friend lines way up in the class definition proper. At that moment it does not yet know the friend functions are themselves templates; it assumes they are non-templates ...

... this assumption causes the compiler to generate a call to the non-template functions, but the linker will give you an "undefined external" error because you never actually defined those non-template functions.

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

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

这与成为 Rational<int> 的 friend 有何不同? ?

编译器/链接器能否区分模板函数和非模板函数?

最佳答案

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

A non-template function is not related to a function template (i.e., it is never considered to be a specialization), even if it has the same name and type as a potentially generated function template specialization.

对于第二个片段,当Rational<int>实例化后,其主体中的友元声明引入了一个非模板函数的声明:

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

关于c++ - 链接器可以区分模板函数和非模板函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55975027/

相关文章:

c++ - Arduino struct does not name 类型错误

c++ - 在模板 C++ 类中初始化 const 的 const 数组

c++ - 为什么下面的程序没有选择与第一个模板参数相同类型的参数?

C++ 模板确定函数返回类型

c++ - VS2015支持魔法静态,那么为什么会出现这个警告呢?

c++ - 类中析构函数定义的 Collect2 错误

C++ 函数和类模板声明

python - 出现错误 : TemplateAssertionError: no filter named 'n' when printing report?

c++ - 在模板类中定义模板化友元函数

c++ - 如何使用 QWaitCondition 实现永远运行的 QThread{} 但在执行此操作时仍需要捕获另一个插槽