9

以下包含朋友声明的代码失败并显示错误(请参阅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>();
}

如果友元声明和成员函数声明的顺序相反,则代码编译没有问题(参见http://ideone.com/y3hiK):

template<class T> void foo() {}

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

int main()
{
   foo<int>();
}

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

4

1 回答 1

7

为了明确表明它是您想要friend在函数名称前面加上的那个函数,::表明它在全局命名空间中。

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

template<class T> void foo() {}

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

int main()
{
   foo<int>();
}

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>
  }
};

...

14.5.3 好友 [temp.friend] 1

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

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

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

— 如果朋友的名字是一个限定ID,并且在指定的类或命名空间中找到了一个函数模板的匹配特化,则朋友声明引用该函数模板特化,否则,

— 名称应为声明(或重新声明)普通(非模板)函数的非限定标识符。

于 2011-12-15T03:50:02.017 回答