命名空间作用域中的运算符在全局范围中隐藏

时间:2013-01-16 08:38:30

标签: 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()
{
    return 0;
}

GCC 4.7错误消息是:

error: no match for 'operator++' in '++bar'
note: candidate is:
note: asdf::Foo& asdf::operator++(asdf::Foo&)
note: no known conversion for argument 1 from 'asdf::Bar' to 'asdf::Foo&'

如果您注释掉该行,则会编译:

Foo& operator++(Foo& foo);

3 个答案:

答案 0 :(得分:14)

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

通过正常的非限定+ ADL查找查找非成员查找,忽略所有类成员函数。因此,全局运算符被词汇更接近的隐藏(并且介入成员函数不会隐藏其他非成员)。

请注意,在名称查找 1 之后,会发生重载解析;在您的情况下,找到了名称operator++,但没有适当的超载。

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


1 Overload resolution (...) takes place after name lookup has succeeded.(C ++标准版)

答案 1 :(得分:8)

不,这不是编译器错误。

对表达式++bar执行了两次名称查找。

  • 常规名称查找搜索封闭的范围和命名空间,直到找到operator++第一个出现。此搜索内部工作,因此最后搜索全局命名空间。在查找运算符函数时,会单独处理成员函数(并且不会停止此搜索)。
  • 依赖于参数的查找将在下一步中搜索并搜索其他类和名称空间,但只搜索与函数参数相关的那些(在本例中为operator++)。

在问题的示例中,正常查找找到asdf::operator++并停止查看 依赖于参数的查找仅将asdf命名空间添加到要搜索的位置,因为这是enum Bar的关联命名空间。因此,无法找到全局operator++

您可以使用名称空间operator++中的使用声明来查找全局asdf

答案 2 :(得分:1)

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

void f(int);

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