在类的内部和外部定义的朋友功能的查找规则之间的区别 [英] Difference between lookup rules for friend function defined inside vs outside of the class

查看:93
本文介绍了在类的内部和外部定义的朋友功能的查找规则之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码:

struct X {
    X() {}
};

struct Y {
    Y() {}
    Y(X) {}
    Y(int) {}
    friend bool operator==(const Y&, const Y&) { return false; }
};

bool f()
{
    return 1 == X();
}

无法编译,并出现以下错误:

fails to compile with the following error:

error: no match for 'operator==' (operand types are 'int' and 'X')
     return 1 == X();

虽然我将operator==的定义移到类之外,但效果很好:

While if I move definition of operator== outside of the class it works just fine:

struct X {
    X() {}
};

struct Y {
    Y() {}
    Y(X) {}
    Y(int) {}
    friend bool operator==(const Y&, const Y&);
};

inline bool operator==(const Y&, const Y&) { return false; }

bool f()
{
    return 1 == X();
}

有人可以解释为什么吗? (理想情况下,引用了一些标准和易于理解的解释/动机.)在此处的答案中: https://stackoverflow.com/a/20114792/1350936 @rightfold提到了

Could someone explain why? (Ideally, with some quote from the standard and human-readable explanation/motivation.) In the answer here: https://stackoverflow.com/a/20114792/1350936 @rightfold mentioned that

即使没有ADL,也可以找到在类外部定义的功能

Functions defined outside of the class can be found even without ADL

但是我不太明白这意味着什么.

But I don't quite understand what it means.

推荐答案

要注意的一件事是,类内部和外部的朋友函数的查找规则不同,请参见

One thing to note is that the lookup rules for friend functions inside and outside the class are different, see [namespace.memdef] (emphasis mine)

如果非本地类中的朋友声明首先声明了一个类, 函数,类模板或函数模板,朋友是 最内层的封闭命名空间的成员. 朋友声明 本身不会使名称对不合格的查找可见或 限定查找. [注意:朋友的名字将显示在 如果在名称空间范围内提供了匹配的声明,则为它的名称空间 (在授予友谊的类定义之前或之后). — 尾注]如果调用了朋友功能或功能模板,则其 可以通过考虑了以下功能的名称查找来找到名称 与函数类型关联的名称空间和类 参数( [basic.lookup.argdep] ).如果名字在朋友声明中 既不合格也不 template-id 并且声明是一个 函数或 elaborated-type-specifier ,以确定 该实体先前是否已被宣布不得考虑任何 作用域位于最内层的封闭命名空间之外. [注意: 朋友声明的形式不能声明该成员的新成员 最内层的封闭命名空间,因此遵循通常的查找规则. — 尾注]

If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup. [ 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 ([basic.lookup.argdep]). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace. [  Note: The other forms of friend declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules. — end note ]

这意味着在您的第一个示例中,编译器看到了与操作数intX的比较,但是没有从Xint的可行转换(或从intX的可行转换,但是X也没有比较运算符).不会尝试将两个操作数都转换为Y,因为根据上面引用的子句,匹配的比较运算符不可见.

That means that in your first example the compiler sees a comparison with operands int and X but there is no viable conversion from X to int (or from int to X but X does not have a comparison operator either). A conversion of both operands to Y is not attempted, because the matching comparison operator is not visible as per the clause quoted above.

同时,您可以在第二个示例中看到具有非显式构造函数的危险,因为两个操作数都隐式转换为可能不相关的类型Y.这可能会产生非常出乎意料的行为,因为编译器认为由于语义不正确而不应编译的代码是有效的.另请参见C ++核心指南C. 46:默认情况下,显式声明单参数构造函数.

At the same time you can see how dangerous it is to have non-explicit constructors in the second example, because both operands are implicitly converted to a possibly unrelated type Y. This might yield very unexpected behaviour because code which should have not compiled due to semantic incorrectness is considered valid by the compiler. See also the C++ Core Guideline C.46: By default, declare single-argument constructors explicit.

这篇关于在类的内部和外部定义的朋友功能的查找规则之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆