C ++ 03和C ++ 11在[temp.friend]的第一段中有:
[编辑引用。首先尝试错过措辞的第二个区别。]
对于非模板声明的友元函数声明:
如果朋友的姓名是合格或不合格的 template-id ,则朋友声明是指功能模板的特化,否则
如果朋友的名字是 qualified-id 并且在指定的类或命名空间中找到匹配的nontemplate函数,则friend声明引用该函数,否则,
[C ++ 03:]如果朋友的名字是 qualified-id ,并且在指定的类或命名空间中找到了函数模板的匹配特化,那么朋友声明是指函数模板专门化,否则,
[C ++ 11:]如果朋友的名字是 qualified-id 并且在指定的类或命名空间中找到匹配的函数模板,那么友元声明是指推导出的该功能模板的专业化,否则,
- 醇>
该名称应为 unqualified-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 ++打印一个有用的警告,说朋友“声明一个非模板函数”,并建议我可能想要这样做。为了清晰和安全,代码可能会获得更多样式点。
但是上面的代码不应该被第三个子弹覆盖并且有效吗? friend声明不是模板声明,并使用 qualified-id 作为名称,而不是 template-id 。并且没有非模板函数声明来匹配第二个项目符号。
这只是两者共同的编译器错误吗?或者我误解了什么,如果有的话,是否有一个程序的例子确实证明了第三个子弹?
答案 0 :(得分:1)
在第// 8行,
修改后的代码为:
friend void N::test< R<T> >( R<T>&);
也是正确的。
friend void N::test<R<T>>(const R<T>&);//one type is friend with one type #1
friend void N::test<>(const R<T>&);// one type is friend with one type #2
我使用了一些代码证明#1等于#2
最后,我试着回答你的问题。我不确定这是对的。
friend void N::test(const R<T>&);
实例化类R时,R<T>
是已知类型。但是,功能是
声明为友元函数并且实际上没有实例化函数模板,那么
朋友功能是一个不存在的功能。从语法的角度来看,
编译器会提示您它是一个函数而不是模板
N::test (r);
在这个地方,函数被实例化,但编译器与
不匹配 在R类声明之前的朋友,因为你没有在R 中声明为模板类,你只需声明一个函数。
答案 1 :(得分:0)
我认为&lt;&gt;从14.8.2.6开始,是扣除的条件,
在declarator-id引用函数模板特化的声明中,执行模板参数推导以识别声明引用的特化。具体而言,这是针对显式实例化(14.7.2),显式特化(14.7.3)和某些朋友声明(14.5.4)而完成的。
在这种情况下,declarator-id不是特化,因此不会发生演绎。
答案 2 :(得分:0)
N :: test是一个模板化函数,它接受一个名为T
的类。它不需要一个名为R<T>
的类。适当地改变功能,它将起作用。
namespace N
{
template <class T>
void test ( const T & );
}
template <class T>
class R
{
friend void N::test ( const R<T> & );
int m;
};
template <class T>
void N::test ( const T & rec ) { rec.m; }
int main ( )
{
R<int> r;
N::test ( r );
}