为何C++中::a::f在::b::f()作用域内可通过未限定名f直接访问?
问题原因说明
你观察到的行为是C++标准规定的*实参依赖查找(ADL/Koenig Lookup)*的典型表现,你对ADL的适用场景存在误解。
核心逻辑解释
我们看b::f(bool)中未限定名f的调用语句:
return f(a::f(value)).value;
这里a::f(value)的返回值是::a::C类型的对象,作为f调用的实参。C++的未限定函数名查找规则明确要求:
除了常规的从当前作用域向外逐层查找的逻辑外,还会额外检索所有实参类型关联的命名空间,将这些命名空间下的同名函数加入重载候选集,这个过程就是ADL。
ADL的触发完全不要求当前所在命名空间和实参关联命名空间存在嵌套关系,仅由调用时传入的实参类型决定,这就是::a::f会被纳入候选的根本原因。
重载决议的匹配逻辑
此时f的重载候选集包含两部分:
- 常规查找得到的
b命名空间下的两个重载:b::f(bool)、b::f(::a::C const&) - ADL补充的
a命名空间下的两个重载:a::f(bool)、a::f(::a::C const&)
传入的实参是::a::C类型的临时对象,a::f(::a::C const&)和b::f(::a::C const&)都是精确匹配,但注意你的代码中后续访问了返回值的.value成员:
- 如果匹配到
b::f(::a::C const&),返回值是bool类型,不存在value成员,编译会直接报错 - 只有匹配到
a::f(::a::C const&),返回值是::a::C类型,存在value成员,代码才能编译通过,你观察到的运行结果正是匹配到a::f的表现。
解决方案
你写的WORK_AROUND方案就是标准解法:使用限定名b::f调用函数,限定名调用不会触发ADL,只会在指定的b命名空间下查找重载,不会纳入a命名空间的f函数,就会按照预期匹配到b::f(::a::C const&)。
内容的提问来源于stack exchange,提问作者p5-vbnekit
相关产品推荐
相关产品推荐

