ADL的陷阱是什么?

前段时间我读了一篇文章,解释了依赖于参数的查找的几个缺陷,但是我再也找不到了。 这是关于获得你不应该访问的东西或类似的东西。 所以我想在这里问:ADL的陷阱是什么?

依赖于参数的查找存在一个巨大的问题。 例如,考虑下面的工具:

#include <iostream> namespace utility { template <typename T> void print(T x) { std::cout << x << std::endl; } template <typename T> void print_n(T x, unsigned n) { for (unsigned i = 0; i < n; ++i) print(x); } } 

这很简单,对吧? 我们可以调用print_n()并将其传递给任何对象,它将调用print来打印对象n次。

其实,事实certificate,如果我们只看这个代码,我们完全不知道 print_n会调用什么函数。 它可能是这里给出的printfunction模板,但它可能不是。 为什么? 依赖于参数的查找。

举一个例子,假设你写了一个类来表示一个独angular兽。 出于某种原因,你还定义了一个名为print (这是个巧合!)的函数,它只是通过写入一个解除引用的空指针来引起程序崩溃(谁知道你为什么这样做,这并不重要):

 namespace my_stuff { struct unicorn { /* unicorn stuff goes here */ }; std::ostream& operator<<(std::ostream& os, unicorn x) { return os; } // Don't ever call this! It just crashes! I don't know why I wrote it! void print(unicorn) { *(int*)0 = 42; } } 

接下来,你写一个创build一个独angular兽的小程序,并打印它四次:

 int main() { my_stuff::unicorn x; utility::print_n(x, 4); } 

你编译这个程序,运行它,然后…崩溃。 “什么?!没办法,”你说:“我只是打电话给print_nprintfunction打印四次独angular兽! 是的,这是真的,但它没有调用你期望它printfunction。 它叫做my_stuff::print

为什么select了my_stuff::print ? 在名称查找过程中,编译器发现print调用的参数是unicorntypes,它是在名称空间my_stuff声明的类types。

由于依赖于参数的查找,编译器在search名为print候选函数时包含该名称空间。 它findmy_stuff::print ,然后在重载parsing过程中将其选为最好的可行候选:不需要转换来调用任一候选print函数, my_stuff::print模板函数优于函数模板,所以非模板函数my_stuff::print是最好的搭配

(如果您不相信这一点,您可以按照原样编译代码,并查看ADL的实际运行情况。)

是的,依赖于参数的查找是C ++的一个重要特性。 实质上需要实现某些语言特性(如重载操作符)的期望行为(考虑stream库)。 也就是说,这也是非常非常有缺陷的,可能会导致非常难看的问题。 有几个build议来解决依赖于参数的查找,但是没有一个被C ++标准委员会接受。