C++ “什么是”呢;参数相关查找“;(又名ADL,或“Koenig查找”)?
关于什么是参数相关查找,有哪些好的解释?许多人也称之为Koenig查找 最好我想知道:C++ “什么是”呢;参数相关查找“;(又名ADL,或“Koenig查找”)?,c++,argument-dependent-lookup,name-lookup,c++-faq,C++,Argument Dependent Lookup,Name Lookup,C++ Faq,关于什么是参数相关查找,有哪些好的解释?许多人也称之为Koenig查找 最好我想知道: 为什么这是件好事 为什么这是一件坏事 它是如何工作的 在Koenig查找中,如果调用函数时未指定其名称空间,则还会在定义参数类型的名称空间中搜索函数名。这就是为什么它也被称为,简而言之 因为Koenig查找,我们可以这样写: std::cout << "Hello World!" << "\n"; STD::CUT 凯尼格查找>或>/Stult>,描述编译器在C++中如何查找不合
- 为什么这是件好事
- 为什么这是一件坏事
- 它是如何工作的
std::cout << "Hello World!" << "\n";
<代码> STD::CUT
<强>凯尼格查找>或
namespace MyNamespace
{
class MyClass {};
void doSomething(MyClass) {}
}
MyNamespace::MyClass obj; // global object
int main()
{
doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
}
在上面的示例中,既没有使用
-声明,也没有使用
-指令,但编译器仍然通过应用Koenig查找正确地将非限定名称doSomething()
标识为命名空间MyNamespace
中声明的函数
它是如何工作的?
该算法告诉编译器不仅要查看局部范围,还要查看包含参数类型的名称空间。因此,在上述代码中,编译器发现作为函数doSomething()
的参数的对象obj
,属于名称空间MyNamespace
。因此,它查看该名称空间以定位doSomething()
的声明
Koenig查找的优势是什么?
正如上面的简单代码示例所示,Koenig查找为程序员提供了方便和易用性。如果没有Koenig查找,程序员将需要重复指定完全限定名,或者使用大量的声明
为什么要批评Koenig查找?
过度依赖Koenig查找会导致语义问题,有时会让程序员措手不及
以为例,这是交换两个值的标准库算法。使用Koenig查找时,使用此算法时必须谨慎,因为:
std::swap(obj1,obj2);
可能不会显示与以下行为相同的行为:
using std::swap;
swap(obj1, obj2);
对于ADL,调用哪个版本的swap
函数取决于传递给它的参数的名称空间
如果存在命名空间a
,并且a::obj1
、a::obj2
和a::swap()
存在,则第二个示例将导致调用a::swap()
,这可能不是用户想要的
此外,如果出于某种原因同时定义了A::swap(A::MyClass&,A::MyClass&)
和std::swap(A::MyClass&,A::MyClass&)
,那么第一个示例将调用std::swap(A::MyClass&,A::MyClass&)
,但第二个示例将不会编译,因为swap(obj1,obj2)
将是不明确的
琐事:
为什么它被称为“Koenig查找”?
因为它是由美国电话电报公司和贝尔实验室的前研究员和程序员设计的
进一步阅读:
-
- 标准C++03/11[basic.lookup.argdep]:3.4.2依赖于参数的名称查找
** 1 **凯尼格查找的定义如Josuttis的书中所定义的,即C++标准库:教程和参考文献*。
也许最好从“为什么”开始,然后再从“如何”开始
当引入名称空间时,其想法是在名称空间中定义所有内容,以便不同的库不会相互干扰。然而,这给运营商带来了一个问题。查看以下代码的示例:
namespace N
{
class X {};
void f(X);
X& operator++(X&);
}
int main()
{
// define an object of type X
N::X x;
// apply f to it
N::f(x);
// apply operator++ to it
???
}
当然,您可以编写N::operator++(x)
,但这将克服运算符重载的全部问题。因此,必须找到一个解决方案,允许编译器查找运算符++(X&)
,尽管它不在范围内。另一方面,它仍然不应该在另一个不相关的名称空间中找到另一个操作符+++
,这可能会使调用变得不明确(在这个简单的示例中,您不会得到不明确,但在更复杂的示例中,您可能会得到)。解决方案是参数相关查找(ADL),这种方式称为ADL,因为查找取决于参数(更确切地说,取决于参数的类型)。由于该方案是由Andrew R.Koenig发明的,因此也常被称为Koenig查找
诀窍在于,对于函数调用,除了常规的名称查找(在使用点查找作用域中的名称)之外,还要在给定给函数的任何参数的类型的作用域中进行第二次查找。因此,在上面的示例中,如果您在main中编写x++
,它不仅在全局范围内查找operator++
,而且在定义x
,N::x
类型的范围内,即在名称空间N
中查找。在那里它找到了一个匹配的操作符++
,因此x++
就可以工作了。但是,将找不到在另一个命名空间中定义的另一个运算符++
,例如N2
。由于ADL不限于名称空间,您还可以在main()中使用f(x)
而不是N::f(x)
namespace N
{
class X {};
void f(X);
X& operator++(X&);
}
int main()
{
// define an object of type X
N::X x;
// apply f to it
N::f(x);
// apply operator++ to it
???
}
std::vector<boost::shared_ptr<int>> v;
auto x = begin(v);