有没有办法避免模板友元声明的外部可见性

Is there a way to avoid the outside visibility of template friend declarations?

本文关键字:声明 友元 外部 可见性 有没有      更新时间:2023-10-16

请看下面的例子:

啊:

class A {
protected:
  template<class T>
  friend void b();
};

BH:

template<class T>
void b() {}

主.cxx:

#include "a.h"
int main()
{
  b<double>();
}

请注意,我忘了在主文件中包含"b.h"。不幸的是,编译器在类 A 中选取了友元声明并编译了 main 函数而不会抱怨。我留下了一个神秘的链接错误,这令人惊讶,因为实例化应该发生在 main.cxx 中:

[joel@fedora-joel friend]$ g++ main.cxx 
/tmp/ccfpaeHw.o: In function `main':
main.cxx:(.text+0x5): undefined reference to `void b<double>()'
collect2: error: ld returned 1 exit status

我的问题是:为什么编译器允许这样做?有没有办法反对它?

ISO/IEC 14882:2003, §11.4, 第 3 段是这样说的:

首先在友元声明中声明的函数具有外部链接 (3.5)。否则,该函数将保留其先前的链接 (7.1.1)。

因此,友元声明兼作函数声明。这允许main调用该函数,因此没有编译器错误。

发生链接器错误的原因是声明没有匹配的函数定义。

我看不到避免这种行为的方法(因为标准规定了它)。这也是有道理的,因为无论如何都需要函数声明才能使朋友声明有效(否则你会有一个未声明函数的朋友声明)。因此,如果友元声明不能兼作函数声明,则必须以其他方式提供函数声明(通过包含适当的标头,例如)。