为什么gcc会在全局命名空间中隐藏重载函数?

8
void f() {}

namespace test
{
void f(int) {}    
void g() { f(); } // error in gcc 6.2.0
}

int main()
{
    test::g();
}

使用 g++ -std=c++1z main.cpp 编译它,输出结果如下:
main.cpp: In function 'void test::g()':
main.cpp:9:4: error: too few arguments to function 'void test::f(int)'
  f(); // error in gcc
    ^
main.cpp:5:6: note: declared here
 void f(int) {}

我的编译器是gcc 6.2.0。

为什么gcc会隐藏全局命名空间中的重载函数?这符合C++标准吗?

1个回答

13

为什么gcc将重载函数隐藏在全局命名空间中?这符合C++标准吗?

是的。简而言之,你不能通过不同的作用域来重载函数。根据未限定名称查找规则,在g()中调用f()时,名称f可以在命名空间test中找到,然后名称查找停止;之后进行重载分辨(基于找到的名称)。这意味着即使全局命名空间中的f()看起来更合适,它也不会被考虑。

(强调我的)

对于一个未经限定的名称,即不出现在作用域解析运算符::的右侧的名称,名称查找会按照下面所述的方式检查作用域,直到它找到至少一个任何类型的声明,此时查找停止,不再检查进一步的作用域。为了编译函数调用,编译器必须首先执行名称查找,对于函数,这可能涉及参数相关的查找,并且对于函数模板,可能会跟随模板参数推导。如果这些步骤产生多个候选函数,则执行重载决议以选择实际调用的函数。using可以将名称引入同一作用域中,即使它们成为真正的重载函数。
namespace test
{
    using ::f;        // introduce the name from global namespace
    void f(int) {}    
    void g() { f(); } // fine
}

3
这是C++中一个已知的怪癖,与派生类中的“重载”隐藏基类中的变量的变体相同,需要在某些情况下使用using Base::foo - Lightness Races in Orbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接