为什么发明了参数依赖查找(ADL)?只是为了我们可以写cout << stuff
而不是std::operator<<(cout, stuff)
?如果是这样,为什么 ADL 不限于运算符而不是所有函数?
如果 C++ 有其他方法可以对内置类型和用户定义类型进行通用输出,例如printf
通过可变参数模板实现类型安全,是否可以阻止 ADL 的引入?
为什么发明了参数依赖查找(ADL)?只是为了我们可以写cout << stuff
而不是std::operator<<(cout, stuff)
?如果是这样,为什么 ADL 不限于运算符而不是所有函数?
如果 C++ 有其他方法可以对内置类型和用户定义类型进行通用输出,例如printf
通过可变参数模板实现类型安全,是否可以阻止 ADL 的引入?
发明 ADL 是为了实现接口原则:
接口原理
对于 X 类,所有函数,包括自由函数,
逻辑上是 X 的一部分,因为它们构成了 X 的接口的一部分。
查看 Herb Sutter关于该主题的本周优秀 Guru 。
如果是这样,为什么 ADL 不限于运算符而不是所有函数?
为什么要人为地限制它?ADL 可能难以实现(当与 C++ 的重载规则结合使用时)1但它是一种非常有用的技术。一方面,它也适用于函数这一事实使得在不导入整个命名空间的情况下使用其他命名空间变得更加容易。
例如,SeqAn 库:
using seqan::String;
String<Char> url = "http://www.seqan.de/";
std::cout << "The URL " << url << " has length " << length(url) << std::endl;
请注意,我在seqan::length
没有限定其全名的情况下使用了该函数。无论如何,ADL 都能找到它。SeqAn 库过度使用此类命名空间范围的函数,并且在每次使用前都使用命名空间名称作为前缀是不切实际的。同样,通常不建议导入命名空间。
对于许多其他库,例如大多数 Boost 库,当然也是如此。
1我相信委员会并没有立即意识到这一点。
为什么不限于运营商?
让我们看一个简单的通用算法:
template <typename FwdIt, typename T>
FwdIt remove(FwdIt first, FwdIt last, T const& value)
{
using std::swap;
FwdIt result = first;
for ( ; first != last; ++first)
if (!(*first == value)) swap(*result++, *first);
return result;
}
它如何与自定义类型及其自己的版本一起使用 swap
?感谢ADL。
正如丹尼尔所说,这就是萨特所说的接口原则。
发明它是为了允许函数多态。这个想法是该功能是一个动词(如“打印”),它只有一个含义。仍然可以有不同的实现,具体取决于动词适用的对象(如 int 和 float 以及 std::string)。
所以我们想要一个词来描述这个概念,但根据它的应用有几个实现。
它适用的是论点。因此,我们需要一种方法来在几个不同类型的参数上使用相同的词,并在需要时使用参数类型相对的实现。
尝试使用 printInt()、printString()、printFloat() 函数编写复杂的串联,您会看到明显的冗长。
另一个原因是它允许检查给定参数类型可用的实现。如果没有可用的实现(甚至不是通用的 - 使用模板),那么编译器会尽快阻止您,并让您知道它没有针对给定参数的动词的实现。
是的,它主要是为操作员发明的。但它也使您能够将非成员函数包含到类的接口中。这是一个非常强大的东西,我非常喜欢。这不再局限于运营商。例如,你可能想cross_product
为你的类定义一个函数vector
——你知道我的意思:)