Sza*_*lcs 45 c++ namespaces friend fully-qualified-naming name-lookup
在类中定义的友元函数的完全限定名称是什么?
我最近看到了一个类似于以下的例子.以下完全限定名称是val()
什么?
#include <iostream>
namespace foo {
class A {
int x;
public:
A(int x = 0) : x(x) { }
friend int val(const A &a) { return a.x; }
};
}
int main() {
foo::A a(42);
// val() found using ADL:
std::cout << val(a) << std::endl;
// foo::val(a); // error: 'val' is not a member of 'foo'
// foo::A::val(a); // error: 'val' is not a member of 'foo::A'
return 0;
}
Run Code Online (Sandbox Code Playgroud)
参数依赖查找是唯一val()
可以找到的方法吗?
不可否认,这并非源于实际问题.我只是希望获得更好的理解.
Sto*_*ica 35
依赖于参数的查找是否可以找到val()的唯一方法?
是的,这是唯一的方法.引用[namespace.memdef]/3中的神圣标准:
如果非本地类中的友元声明首先声明了类,函数,类模板或函数模板,则该友元是最内层封闭命名空间的成员.友元声明本身不会使名称对非限定查找或限定查找可见.
因此,虽然val
是一个成员foo
,但仅从朋友声明中查找是不可见的.要使其可见,需要使用类外定义(也是声明).对于内联定义(并且没有类外声明),这意味着ADL是调用该函数的唯一方法.
作为一个额外的好处,C++曾经有过"朋友名注射"的概念.然而,这已被删除,并且ADL的规则被调整为替代.更详细的概述可以在WG21论文N0777(pdf)中找到.
C++标准[7.3.1.2/3(ISO/IEC 14882:2011)]:
首先在名称空间中声明的每个名称都是该名称空间的成员.如果非本地类中的友元声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员. 在非命名查找(3.4.1)或限定查找(3.4.3)之前找不到朋友的名称,直到在该命名空间范围内提供匹配声明(在授予友谊的类定义之前或之后).如果调用了友元函数,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2).如果友元声明中的名称既不是限定语句也不是模板标识,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内层封闭命名空间之外的任何范围.