简体   繁体   English

clang / g ++与朋友功能的区别

[英]clang/g++ difference with friend function

Why code below well compiled in g++ but get error on clang? 为什么下面的代码用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;
}

Proof links: g++ / clang++ 证明链接: g ++ / clang ++

When I moved friend function to global namespace, code well compiled for both compilers ( clang++ / g++ ). 当我将friend函数移动到全局命名空间时,为两个编译器编译好的代码( clang ++ / g ++ )。

Which implementation in this case is more C++ Standart compatible? 在这种情况下,哪种实现更兼容C ++ Standart?

Clang is correct here. Clang在这里是正确的。 Friend functions defined inside classes can only be found using argument-dependent-lookup on their arguments, not by ordinary lookup. 在类中定义的友元函数只能在其参数上使用参数依赖查找而不是通过普通查找来查找。 Because Print is not an associated scope to Object , the operator<< should not be found. 因为Print不是Object的关联范围,所以不应找到operator<< Partial quote from the Standard: 标准的部分引用:

7.3.1.2 Namespace member definitions [namespace.memdef] 7.3.1.2命名空间成员定义[namespace.memdef]

3 Every name first declared in a namespace is a member of that namespace. 3首先在名称空间中声明的每个名称都是该名称空间的成员。 If a friend declaration in a non-local class first declares a class, function, class template or function template97 the friend is a member of the innermost enclosing namespace. 如果非本地类中的友元声明首先声明了类,函数,类模板或函数模板97,则该友元是最内层封闭命名空间的成员。 The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). 友元声明本身不会使名称对非限定查找(3.4.1)或限定查找(3.4.3)可见。 [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). [注意:如果在命名空间范围内提供匹配的声明(在授予友谊的类定义之前或之后),则朋友的名称将在其命名空间中可见。 — end note ] If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). - 结束注释] 如果调用了友元函数或函数模板,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2)。

As @sehe mentions, the proper way to add an operator<< to Object is to define it as a global function (using Object interface) or as a friend function inside itself (using private functions from Object ), not in some auxiliary class. 正如@sehe所提到的,向Object添加operator<<的正确方法是将其定义为全局函数(使用Object接口)或作为friend函数(使用Object private函数),而不是在某些辅助类中。 See also Herb Sutter's old GotW column "What's in a class?" 另见Herb Sutter的旧GotW专栏“课堂上有什么?”

The iffy thing is to declare an static (friend) operator in another class (that is unrelated). iffy的事情是在另一个类(不相关的)中声明一个静态(朋友)运算符。

  1. You could just create it in the surrounding scope, there's 你可以在周围的范围内创建它

    • no difference semantically 在语义上没有区别
    • no reason to have it a friend (as Printer is not used any way) 没有理由让它成为朋友(因为Printer没有以任何方式使用)
    • you can still make it a friend if you needed to 如果你需要,你仍然可以成为朋友

    Live On Coliru 住在Coliru

  2. Alternatively, make the other class related ; 或者, 使其他类相关 ;

    There are many ways to associate namespaces (§3.4.2) with a type for function lookup. 将命名空间(第3.4.2节)与函数查找类型相关联的方法有很多种。 For example this hack would be enought to associate the Print class namespace with the Object type so ADL will still work: 例如,这个hack应该将Print类命名空间与Object类型相关联,因此ADL仍然可以工作:

     template <typename> struct Object_ {}; typedef Object_<class Print> Object; 

    See this Live On Coliru as well 请看这个Live On Coliru

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM