模板专业化的朋友声明失败

Gen*_*yev 8 c++ templates friend language-lawyer name-lookup

以下包含好友声明的代码失败并显示错误(请参阅http://ideone.com/Kq5dy):

template<class T> void foo() {}

template<typename T>
class A {
   void foo();
   friend void foo<T>(); // error: variable or field 'foo' declared void
};

int main()
{
   foo<int>();
}
Run Code Online (Sandbox Code Playgroud)

如果朋友声明和成员函数声明的顺序颠倒了,那么代码编译没有问题(参见http://ideone.com/y3hiK):

template<class T> void foo() {}

template<typename T>
class A {
   friend void foo<T>();
   void foo();
};

int main()
{
   foo<int>();
}
Run Code Online (Sandbox Code Playgroud)

如果朋友声明不包含模板专业化,则不会发生这种情况:非模板朋友可以,以及模板朋友.在模板专门化中使用限定名称也允许编译代码.我的问题是为什么第一个例子失败了?似乎编译器在朋友声明点查找类范围中的名称,仅用于模板专业化?标准中的哪个行为被指定?

Fil*_*efp 7

为了明确表示你想要friend的功能是在函数名称之前加上::它来表示它在全局命名空间中.

编译并执行您想要的代码片段:

template<class T> void foo() {}

template<typename T>
class A {
   void foo();
   friend void ::foo<T>();
};

int main()
{
   foo<int>();
}
Run Code Online (Sandbox Code Playgroud)

n1905.pdf

3.4/9名称查找

在授予友谊的类中内联定义的朋友函数(11.4)的定义中使用的名称的名称查找应按照成员函数定义中的查找进行.如果友元函数未在授予友谊的类中定义,则友元函数定义中的名称查找应按照在命名空间成员函数定义中查找所述进行.

您的代码段无法编译,原因与下面的代码无法编译的原因相同.

template<class T> void foo () {}

template<typename T>
struct A { 

  void foo (); 

  void func () {
    foo<T> (); // when performing the name lookup A::foo is
               // found before ::foo<T>
  }
};
Run Code Online (Sandbox Code Playgroud)

...

14.5.3朋友[temp.friend] 1

类或类模板的朋友可以是函数模板或类模板,函数模板或类模板的特化,或普通(非模板)函数或类.对于不是模板声明的友元函数声明:

- 如果朋友的姓名是合格或不合格的模板ID,则朋友声明指的是函数模板的特化,否则

- 如果朋友的名称是quali-ed-id并且在指定的类或命名空间中找到匹配的非模板函数,则friend声明引用该函数,否则,

- 如果朋友的名称是quali-ed-id并且在指定的类或命名空间中找到了函数模板的匹配特化,则friend声明引用该函数模板特化,否则,

- 名称应为声明(或重新声明)普通(非模板)函数的unquali fi-id.