C++ 不使用<&燃气轮机;
C++03和C++11在[temp.friend]的第一段中有: [已编辑的引文。第一次尝试遗漏了第二次措辞差异。] 对于不是模板声明的友元函数声明:C++ 不使用<&燃气轮机;,c++,templates,language-lawyer,C++,Templates,Language Lawyer,C++03和C++11在[temp.friend]的第一段中有: [已编辑的引文。第一次尝试遗漏了第二次措辞差异。] 对于不是模板声明的友元函数声明: 如果友元的名称是限定的或非限定的模板id,则友元声明引用函数模板的专门化,否则 如果友元的名称是限定id,并且在指定的类或命名空间中找到匹配的非模板函数,则友元声明引用该函数,否则 [C++03:]如果友元的名称是限定id,并且在指定的类或命名空间中找到函数模板的匹配专门化,则友元声明引用该函数模板专门化,否则 [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);
}
模板类R;
名称空间N{
模板无效测试(常数R&);
}
模板
R类{
friend void N::test(const R&);//8
int m;
};
模板
void N::test(constr&rec){rec.m;}
int main(){
R;
N:试验(r);
}
当然,如果我把第8行改为
friend void N::test<>(const R<T>&);
friend void N::test(const R&);
第一个项目符号适用,程序被接受。g++打印了一条有用的警告,说friend“声明了一个非模板函数”,并建议我可能确实要这样做。为了清晰和安全,代码可能会得到更多的样式点
但是上面的代码不应该包含在第三个项目符号中并且有效吗?好友声明不是模板声明,并使用非模板id的限定id作为名称。并且没有与第二个项目符号匹配的非模板函数声明
这仅仅是两者共同的编译器错误吗?或者我误解了什么,如果是的话,是否有一个程序的例子证明了第三个项目?我认为这是进行扣除的一个条件,因为从14.8.2.6开始
在声明器id引用函数模板专门化的声明中,将执行模板参数推断以标识声明所引用的专门化。具体来说,这是为显式实例化(14.7.2)、显式专门化(14.7.3)和某些友元声明(14.5.4)而做的
在这种情况下,声明器id不是专门化,因此不会进行任何推导。N::test是一个模板化函数,它使用一个名为
T
的类。它不接受名为R
的类。适当地改变功能,它就会工作
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 );
}
名称空间N
{
模板
孔隙试验(常数T&);
}
模板
R类
{
朋友空N::测试(常数R&);
int m;
};
模板
void N::test(const T&rec){rec.m;}
int main()
{
R;
N:试验(r);
}
在第//8行,
修改代码为:
friend void N::test(R&);
也正确。
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
在这里,函数被实例化,但编译器与
friend在R类中声明之前,因为您没有在R类中声明为模板
类,您只需声明一个函数。+1有趣。我怀疑
是“朋友的名字”的一部分。@johndilling:qualified id包括其他备选模板id,因此是的,f
是一个完全限定的id。@johndilling是的,令牌
是模板id的一部分。名称可以是标识符、运算符和函数id,文字运算符id、转换函数id或模板id[basic/4]。@aschepler:这就是您的答案?相关:,这似乎意味着示例格式正确。[temp.arg.explicit]/3说“如果可以推导出所有模板参数,则可以省略所有模板参数;在这种情况下,空模板参数列表
本身也可能被忽略。“声明器id从来不是专门化,它是一个名称。它指的是专门化,请参见[temp.fct.spec]/1。您能详细说明一下吗?为什么[temp.friend]/3不适用?例如,对于像模板void N::test(const R&);
(在全局名称空间中;保留模板void test(const R&);
)这样的显式实例化,演绎效果很好。g++4.9和clang++3.4(甚至clang++3.6)。您使用了什么编译器?它也类似于。我使用MSVC 2013。如果我们查看需求列表:1)朋友的名字没有模板化,因此我们转到2。2)朋友的名字是一个限定id,但它没有匹配的非模板函数(N::test是模板化的)因此我们得到了3.3)友元的名称是一个限定id,并且在名称空间N中找到了匹配的函数模板,因此我们可以使用我们的函数,因此它尝试使用第一个定义,并对函数模板进行专门化,这是不存在的…除非您使用找到的修复操作。函数模板的专门化:模板化类的成员函数:我不知道为什么我的代码对您不起作用,但看起来OP的修复应该如此。
friend void N::test(const R<T>&);
N::test (r);