C++03和C++11在[temp.friend]的第一段中有:
[编辑引用。第一次尝试错过了措辞的第二个差异。]
对于不是模板声明的友元函数声明:
如果朋友的名字是合格或不合格的 template-id,朋友声明是指一个函数模板的特化,否则
如果朋友的名字是一个qualified-id,并且在指定的类或命名空间中找到了一个匹配的非模板函数,朋友声明引用那个函数,否则,
[C++03:] 如果朋友的名字是一个qualified-id,并且在指定的类或命名空间中找到了一个函数模板的匹配特化,则朋友声明引用该函数模板特化,否则,
[C++11:] 如果朋友的名字是一个qualified-id,并且在指定的类或命名空间中找到了一个匹配的函数模板,朋友声明是指该函数模板的推导特化,否则,
该名称应为声明(或重新声明)普通(非模板)函数的非限定 ID 。
[措辞的变化对我来说似乎是澄清。虽然我猜可能有不同的方式来解释 C++03 中关于“在类或命名空间中寻找专业化”的措辞。]
我对第三颗子弹很好奇。我编写此代码以尝试满足其要求,但 g++ 4.8.1 和 clang++ 3.4 都拒绝该代码,无论是使用 -std=c++03 还是 -std=c++11:
template <class T> class R;
namespace N {
template <class T> void test(const R<T>&);
}
template <class T>
class R {
friend void N::test(const R<T>&); // 8
int m;
};
template <class T>
void N::test(const R<T>& rec) { rec.m; }
int main() {
R<int> r;
N::test(r);
}
当然,如果我将第 8 行更改为
friend void N::test<>(const R<T>&);
第一个项目符号适用并且程序被接受。g++ 打印一个有用的警告,说朋友“声明了一个非模板函数”,并建议我可能想要这样做。为了清晰和安全,代码可能会获得更多样式点。
但是上面的代码不应该被第三个项目符号覆盖并且有效吗?朋友声明不是模板声明,它使用不是模板ID 的限定ID作为名称。并且没有与第二个项目符号匹配的非模板函数声明。
这只是两者共同的编译器错误吗?或者我是否误解了某些东西,如果是这样,是否有一个程序示例可以演示第三个项目符号?