C++ 命名空间范围中的运算符在全局范围中隐藏另一个

C++ 命名空间范围中的运算符在全局范围中隐藏另一个,c++,namespaces,name-lookup,C++,Namespaces,Name Lookup,这是一个编译器错误吗 template <typename T> T& operator++(T& t) { return t; } namespace asdf { enum Foo { }; enum Bar { }; Foo& operator++(Foo& foo); void fun() { Bar bar; ++bar; } } // end namespace asdf int main() {

这是一个编译器错误吗

template <typename T>
T& operator++(T& t)
{
    return t;
}

namespace asdf {

enum Foo { };
enum Bar { };

Foo& operator++(Foo& foo);

void fun()
{
    Bar bar;
    ++bar;
}

} // end namespace asdf

int main()
{
    return 0;
}
如果您注释掉该行,它将编译:

Foo& operator++(Foo& foo);

不,这不是一个错误。考虑了三组并行运算符。成员、非成员运算符和内置运算符

非成员函数通过普通的非限定+ADL查找进行查找,忽略所有类成员函数。因此,全局运算符被一个词法更接近的运算符隐藏(并且中间的成员函数不会隐藏其他非成员)

注意,重载解析发生在名称查找1之后;在您的案例中,找到了名称
operator++
,但没有适当的重载

如果Bar是全局声明的,和/或命名空间asdf中的其他运算符,ADL(在前一种情况下)或普通非限定查找(在后一种情况下)会将该运算符拖入



1:
重载解析(…)在名称查找成功后发生。
(C++标准)

不,这不是编译器错误

对表达式
++bar
执行两个名称查找

  • 常规名称查找搜索封闭范围和名称空间,直到找到第一个出现的
    operator++
    。这种搜索是由内而外进行的,因此全局名称空间是最后一次搜索的。在查找运算符函数时,成员函数将单独处理(不要停止此搜索)
  • 依赖于参数的查找将在下一步开始并搜索其他类和名称空间,但只搜索与函数参数相关的类和名称空间(
    operator++
在问题中的示例中,常规查找查找到
asdf::operator++
并停止查找。
依赖于参数的查找仅将
asdf
命名空间添加到要搜索的位置,因为这是
enum Bar
的关联命名空间。因此,无法找到全局
运算符+


您可以在命名空间
asdf

中使用using声明找到全局
运算符+++
,重载仅适用于在同一范围内定义的名称。一旦编译器找到一个匹配的名称,它就不会在外部作用域中查找,即使它找到的名称应用于无法使用的内容。这与运营商无关;如果代码使用函数名的方式与使用运算符++的方式相同,则会出现相同的错误。例如:

void f(int);

struct C {
void f(const C&);
void g() {
    f(3); // error: f(const C&) can't be called with argument 3
};

……我不这么认为。VC++也会生成同样的结果。@KarthikT:我不确定链接的代码如何支持“Isa bug”参数。我不确定这是否足够详细。如果不匹配,是否应该查找下一个封闭名称空间?@phresnel:但是名称
operator++
如何构成
operator++
的不匹配?在名称查找过程中,只有名称才是相关的。@Bartvaningeschenau:我是在怂恿litb添加这个细节(如果你愿意,试着从提问者的角度来思考);“照目前的情况,我认为我还不能提高投票率。”弗雷斯内尔可以通过编辑来改进答案。你描述的第一个子弹不考虑类作用域。也就是说,即使在类成员函数中使用运算符表达式,也可以找到名称空间作用域运算符,即使在与非DL相关的名称空间作用域中,尽管存在同名的成员运算符。@Johanneschaub litb:这是C++03和C++11之间的更改吗?因为我在C++03第3.4.1条[basic.lookup.unqual]中找不到这样的异常。规则在13.3.1.2:-)中指定。我正在编译器之间移植代码。编译器A接受这个问题中的代码(它显然还包括用于重载解析的全局运算符)-这是否应该被视为编译器错误?@MattMcNabb:是的,如果编译器A接受这个问题中的代码,当以一致性模式调用时,那么编译器A有一个错误。
void f(int);

struct C {
void f(const C&);
void g() {
    f(3); // error: f(const C&) can't be called with argument 3
};