为什么下面的代码用g ++编译好但是在clang上得到错误?
#include <iostream>
class Object {};
class Print
{
public:
template <typename CharT>
inline friend std::basic_ostream<CharT> & operator<<(std::basic_ostream<CharT> & out, const Object&)
{
return (out << "object");
}
static void f( const Object& str )
{
std::cout << str;
}
};
int main()
{
std::cout << Object() << std::endl;
return 0;
}
证明链接: 克++ / 铛++
当我将友元函数移动到全局命名空间时,为两个编译器编译好的代码(铛++ / 克++)。
在这种情况下,哪种实现更兼容C ++ Standart?
Clang在这里是正确的。在类中定义的友元函数只能在其参数上使用参数依赖查找而不是通过普通查找来查找。因为 Print
不是相关的范围 Object
, operator<<
不应该找到。标准的部分引用:
7.3.1.2命名空间成员定义[namespace.memdef]
3首先在名称空间中声明的每个名称都是其成员
命名空间。如果非本地类中的朋友声明首先声明
朋友是一个类,函数,类模板或函数模板97
最内层封闭命名空间的成员。 朋友的声明
本身不会使名称对非限定查找可见(3.4.1)
或合格的查找(3.4.3)。 [注意:朋友的名字将是
如果在提供匹配的声明,则在其命名空间中可见
命名空间范围(在类定义授予之前或之后)
友谊)。 - 结束说明] 如果朋友的功能或功能模板是
调用时,可以通过查找的名称查找找到其名称
来自名称空间的函数和与类型相关联的类
函数参数(3.4.2)。
正如@sehe提到的那样,添加一个正确的方法 operator<<
至 Object
是将其定义为全局函数(使用 Object
接口)或作为 friend
内部功能(使用 private
功能来自 Object
),而不是某些辅助类。另见Herb Sutter的旧GotW专栏 “课堂上有什么?”
iffy的事情是声明一个静态(朋友)运算符 另一个 类(不相关)。
你可以在周围的范围内创建它
- 在语义上没有区别
- 没有理由把它当成朋友(如
Printer
是不是以任何方式使用)
- 如果你需要,你仍然可以成为朋友
住在科利鲁
或者, 使 另一堂课 有关;
将命名空间(第3.4.2节)与函数查找类型相关联的方法有很多种。例如,这个黑客将被认为是关联的 Print
class命名空间 Object
类型所以ADL仍然有效:
template <typename> struct Object_ {};
typedef Object_<class Print> Object;
看到这个 住在科利鲁 同样