在 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)’
这是我目前的理解:
- 朋友非成员函数
anotherFeed(int)
是implicitly inline.
- 即使
anotherFeed(int)
是inline
,我们也不能在同一个翻译单元中定义相同的函数(内联与否无关紧要)
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)
的重新声明,由于这个声明对应了一个定义,根据我回答开头引用的语句,你会得到重新定义错误。
我正在使用 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)’
这是我目前的理解:
- 朋友非成员函数
anotherFeed(int)
是implicitly inline. - 即使
anotherFeed(int)
是inline
,我们也不能在同一个翻译单元中定义相同的函数(内联与否无关紧要) 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)
的重新声明,由于这个声明对应了一个定义,根据我回答开头引用的语句,你会得到重新定义错误。