在 class 模板中定义友元函数时重定义错误

Redefinition error when defining friend function inside class template

我正在使用 here 列出的书籍学习 C++ 中的 友元声明。所以在阅读之后,为了测试我对这个概念的理解,我写了下面的程序,它的输出我无法理解:

template<typename T>
struct Name
{
  
  friend void anotherFeed(int x)//anotherFeed is implicitly inline and its definition is generate only when we use this nonmember function so why are we getting error at instiantiation?
  {
  }
 
};
int main()
{
    Name<int> s;
    Name<double> p;//error here. My question is that this is instiantiation of the class template Name<double> and not a call to anotherFeed so why do we get error here?
}

以上程序报错如下:

error: redefinition of ‘void anotherFeed(int)’

这是我目前的理解:

  1. 朋友非成员函数anotherFeed(int)implicitly inline.
  2. 即使anotherFeed(int)inline,我们也不能在同一个翻译单元中定义相同的函数(内联与否无关紧要)
  3. anotherFeed(int)定义生成只有当我们use/call这个函数就像一个非模板class 模板的成员函数。

我的问题是:假设我的理解(以上3点)是正确的,因为我没有called/used anotherFeed 所以它的定义不应该生成,我们不应该得到创建 class 模板实例时出现重定义错误。只有当我们使用这些实例调用 anotherFeed 时,我们才应该得到重定义错误。那么为什么我们在创建 class 模板实例时会出错。以上3点有没有错

总结

我读到这些函数(非模板成员函数和朋友非模板函数)的定义仅在使用时实例化。也就是说,

Name<int> s;    
Name<double> p; //this should work in principle because this does not instantiate the definition of anotherFeed(int)

但这并没有发生。 Why/How?

免费功能

friend void anotherFeed(int x){}

不依赖于模板参数,因此,只有这个自由函数在您的示例中被 定义 两次。仅将其设为前向 声明

template<typename T>
struct Name {
    friend void anotherFeed(int x);
};

并在 class 定义之外定义它

void anotherFeed(int x) {}

一切顺利。

对于函数模板,可以在不实例化其定义的情况下实例化其声明。

这将实例化除函数体之外的所有内容(或多或少)。

您的函数声明已实例化when the class is instantiated。当(并且如果)您实际调用该函数时,它的定义被实例化。

我找不到正确的标准引用,但显然编译器不需要实例化定义来拒绝重复的实例化声明。

此问题已解决 here

However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.

因此,即使您的程序中 anotherFeed(int) 定义 没有实际实例化,编译器仍然需要 诊断同一翻译单元多个定义 好像定义每次都被实例化声明被实例化。

所以当你写道:

Name<double> p; //instantiate a declaration of anotherFeed(int) for the second time. 

上面的语句,实例化了anotherFeed(int)的重新声明,由于这个声明对应了一个定义,根据我回答开头引用的语句,你会得到重新定义错误。