考虑以下代码:
namespace Foo1 {
void add( int ) {}
void subtract( int ) {}
}
namespace Foo2 {
class Bar {
public:
friend void add( Bar ) {}
};
void subtract( Bar ) {}
void xxx() {
int i = 0;
using namespace Foo1;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
}
Run Code Online (Sandbox Code Playgroud)
在中,Foo2::xxx()我使用using命名空间来访问Foo1::add和Foo1::subtract。调用减法显然是一个错误,因为Foo2::subtract
隐藏名称。但是Foo2::add不应真正可见,Foo2因为只能使用ADL找到它,并且不应隐藏Foo1::add。我的理解正确吗?
我已经在多个版本的MSVC和gcc上尝试了上面的代码。前者一直拒绝add(i)通话,但是错误消息对我来说并不明确。后者一直接受它。以下哪一项(如果有)是正确的?
我认为海湾合作委员会就在这里。
[namespace.memdef](重点是我的)
3如果非本地类中的好友声明首先声明了一个类,函数,类模板或函数模板,则该好友是最内层的命名空间的成员。朋友声明本身不会使名称对不合格查找([basic.lookup.unqual])或合格查找([basic.lookup.qual])可见。[?注:如果在名称空间范围内(在授予友谊的类定义之前或之后)提供了匹配的声明,则朋友的名称将在其名称空间中可见。?-?end note?]如果调用了朋友函数或函数模板,则可以通过名称查找来找到其名称,该名称查找考虑了与函数参数类型相关联的名称空间和类中的函数([basic.lookup.argdep]) 。
因此,不合格add( i )的对象本身不应找到的声明add( Bar ),这意味着查找应继续并考虑using指令引入的名称。而且由于参数不是类类型的,因此ADL是不可能的。我断定那add( Bar ) 不应该隐藏add( int )。