C++ 普通查找与参数相关查找
c++ ordinary lookup vs argument dependent lookup
考虑 http://en.cppreference.com/w/cpp/language/adl 中描述的此示例:
namespace A {
struct X;
struct Y;
void f(int);
void g(X);
}
namespace B {
void f(int i) {
f(i); // calls B::f (endless recursion)
}
void g(A::X x) {
g(x); // Error: ambiguous between B::g (ordinary lookup)
// and A::g (argument-dependent lookup)
}
void h(A::Y y) {
h(y); // calls B::h (endless recursion): ADL examines the A namespace
// but finds no A::h, so only B::h from ordinary lookup is used
}
}
我想知道为什么会出现歧义,因为 ADL 规则没有被考虑在内,如果
"通常由非限定查找生成的查找集包含以下任何内容"。
这里 B::g 可以通过非限定查找找到,如 http://en.cppreference.com/w/cpp/language/unqualified_lookup 中所述,这要归功于规则
对于函数定义中使用的名称,无论是在其主体中还是作为默认参数的一部分,其中函数是用户声明或全局命名空间的成员,则在使用名称之前搜索使用该名称的块,然后在该块开始之前搜索封闭块, 等等,直到到达作为功能体的块。然后搜索声明函数的命名空间,直到使用该名称的函数的定义(不一定是声明(,然后是封闭的命名空间等。
那么我的问题是为什么在这种情况下考虑 ADL 规则?
完整引用是
首先,如果由通常的非限定查找生成的查找集包含以下任何内容,则不考虑依赖于参数的查找:
- 类成员的声明
块- 范围内的函数声明(不是使用声明(
任何不是函数或函数- 模板的声明(例如,函数对象或名称与正在查找的函数名称冲突的另一个变量(
这意味着仅当非限定查找产生上述三个结果之一时,才会忽略 ADL。 由于我们不处理类成员,因此该函数是在命名空间范围而不是块作用域声明的,我们只找到我们继续使用 ADL 的函数。
为什么在这种情况下考虑ADL(参数相关查找(规则?
因为关联的命名空间中可能有更好的匹配项。 例如:
void f(void*);
namespace A {
struct X;
void f(X*);
}
int main() {
A::X* x = 0;
f(x); // A::f is the best match.
}
此机制通常用于swap
功能:
std::swap
可能专门用于用户定义类型的命名空间std
,但 ADL 找不到此类专用化(命名空间std
不是用户定义类型的关联命名空间(。使用户定义类型可交换的预期方法是在与类型相同的命名空间中提供非成员函数交换:有关详细信息,请参阅可交换。在
std::swap
和用户定义的swap()
都可见的上下文中使用非限定函数调用swap()
,此类型的任何左值或右值都可以与其他类型的任何左值或右值交换。
谢谢你的这个问题。我自己来这里寻找答案,我想我已经能够想出一个属于这个规则的例子
如果通常由非限定查找生成的查找集包含以下任何一项,则不考虑依赖于参数的查找:
- 块
。
范围内的函数声明(不是使用声明(
并确实关闭了 ADL。
#include <iostream>
namespace x {
struct type {};
void fn(type) { std::puts("ADL"); }
}
int main() {
// Forward function declaration within the function scope.
// This way "Regular" gets printed out.
// Comment this declaration out and you'll get "ADL".
void fn(x::type);
fn(x::type{});
return 0;
}
void fn(x::type) { std::puts("Regular"); }
如果你把这个前陈述放在主要之前,你会得到一个模棱两可的调用,因为通常的非限定名称查找和 ADL 都会启动。但是在函数范围内声明了函数后,一切都按承诺工作。
仍然不确定在野外多久可以找到一次。至少,我还没有见过这样的东西,也很难想象这样的编码技巧在哪里会有什么好处。
- 参数相关查找和流运算符重载
- 编译器在C++中调用另一个函数时,在参数中查找已删除的构造函数
- 当数组在C++中用作参数时,查找数组的元素数
- C++ 普通查找与参数相关查找
- 运算符<<依赖于参数的查找不在全局命名空间中查找
- 查找可变参数列表的字符串格式指定符
- 在参数相关查找之前进行模板替换的任何方法(或解决方法?
- 如何查找/删除具有特定参数的结构向量的元素
- C 中的参数查找
- 支持与参数有关的查找的编译器
- 为什么在其他函数中声明的函数不参与参数相关查找?
- 使用查找表选择具有运行时索引的可变参数类型
- 为什么在这种情况下不考虑依赖于参数的查找?
- 数组作为函数参数查找数组长度时出错
- 仅通过参数查找重载地址
- 重载函数查找轮廓的实例与参数列表不匹配
- 我如何避免使用依赖于参数的查找明确专门化模板化功能
- 查找参数包的唯一值的数目
- 查找参数时出错
- 用于查找参数是否为类的不同模板语法