为什么 GCC 允许在不首先使用其命名空间的情况下调用此函数?

2022-01-04 00:00:00 namespaces scope c++
<块引用>

可能的重复:
什么是参数相关查找"?(又名 ADL,或Koenig Lookup")?
为什么 C++ 参数作用域会影响函数查找命名空间?

今天我遇到了这种奇怪的行为.我可以在不先使用命名空间 Strange 的情况下调用奇怪的Fn,但不允许调用奇怪的Fn2 为什么?

命名空间奇怪{结构体{};无效的奇怪Fn(X&){}无效的奇怪Fn2(int){}}int main(){奇怪::X x;奇怪的Fn(x);//GCC 允许调用这个函数.奇怪的Fn2(0);//错误:未在此范围内声明奇怪的 Fn2.返回0;}

C++ 编译器如何解析符号的作用域?

解决方案

这叫做 参数依赖查找(或 Koenig 查找)

基本上,如果无法解析符号,编译器将查看参数的命名空间.

第二个函数调用失败,因为strangeFn2在当前命名空间中不可见,也没有在其参数类型(int)的命名空间中定义

您可以看到这如何与运算符函数配合使用:

 std::complexc, d;c += d;//没有 ADL 就无法真正工作

或无处不在的 iostream 操作符:

 std::string s("hello world");std::cout <<s<

为了好玩,这就是 没有 ADL(没有 using 关键字...)的 hello world 的样子:

 std::string s("hello world");std::operator<<(std::cout, s).operator<<(std::endl);//丑陋的!

在存在函数模板的情况下,ADL 和重载解析存在一些隐蔽的极端情况,但我现在将它们排除在答案的范围之外.

Possible Duplicate:
What is "Argument-Dependent Lookup" (aka ADL, or "Koenig Lookup")?
Why does C++ parameter scope affect function lookup within a namespace?

Today I experienced this weird behavior. I can call strangeFn without using namespace Strange first, but does not allow calling strangeFn2 Why?

namespace Strange
{
    struct X
    {
    };
    void strangeFn(X&) {}
    void strangeFn2(int) {}
}

int main()
{
    Strange::X x;
    strangeFn(x);    // GCC allows calling this function.
    strangeFn2(0);   // Error: strangeFn2 is not declared in this scope.
    return 0;
}

How does C++ compilers resolve the scope of the symbols?

解决方案

This is called Argument Dependent Lookup (or Koenig Lookup)

Basically, if a symbol couldn't be resolved, the compiler will look into the namespace(s) of the argument(s).

The second function call fails, because strangeFn2 isn't visible in the current namespace, neither is it defined in the namespace of it's parameter type (int)

You can see how this works well with operator functions:

 std::complex<double> c, d;
 c += d; // wouldn't really work without ADL

or the ubiquitous iostream operators:

 std::string s("hello world");
 std::cout << s << std::endl; // Hello world would not compile without ADL...

For fun, this is what hello world would look like without ADL (and without using keyword...):

 std::string s("hello world");
 std::operator<<(std::cout, s).operator<<(std::endl); // ugly!

There are shadowy corner cases with ADL and overload resolution in the presence of function templates, but I'll leave them outside the scope of the answer for now.

相关文章