也许我对 C++ 不太了解,但我发现 C++ 编译器的行为难以理解(在我看来是危险的)。
MSVC、g++ 和 Clang 的行为相同。
问:为什么函数
::a::f
在f
内可见为b::f(bool)
?
namespace a {
struct C {
bool value;
C(): value(false) {}
C(C const &): value(false) {}
explicit C(bool value): value(value) {}
};
inline C f(bool value) { return C(value); }
// why this function is visible as `f` inside `b::f(bool)`?
inline C f(C const &value) { return C(not value.value); }
}
namespace b {
inline bool f(::a::C const &value) { return value.value; }
inline bool f(bool value) {
#ifdef WORK_AROUND_PROBLEM
return b::f(a::f(value));
#else
// why `::a::f` is visible as `f` here?
return f(a::f(value)).value;
#endif
}
}
int main(int, char **) {
if (b::f(false) or (! b::f(true))) return 1;
if (b::f(0)) return 2;
if (b::f(a::C(false)) || (! b::f(a::C(true)))) return 3;
return 0;
}
Argument dependent lookup
解释。这是由于参数依赖查找。
如果函数采用自定义类型的参数,则在调用函数时会在声明该类型的命名空间中搜索可行的重载。
f(a::f(value))
正在将
C
传递给 f
。这会触发 ADL,因此除了在周围范围中进行名称查找之外,编译器还会在 namespace a
中搜索,因为 C
是在那里声明的。
这是定义自由函数运算符重载时最常见的重要特征。我们可以将它们放在与相关类型相同的命名空间中,
ADL
将确保在名称查找中找到重载,而不会污染全局/外部作用域。