为什么要发明参数依赖查找?

发布于 2024-10-04 00:45:35 字数 245 浏览 0 评论 0 原文

为什么要发明参数依赖查找(ADL)?是不是我们就可以这样写 cout << stuff 而不是 std::operator<<(cout, stuff)?如果是这样的话,为什么 ADL 不限于运算符而不是所有函数?

如果 C++ 有其他方法来执行内置类型和用户定义类型的通用输出(例如通过可变参数模板的类型安全 printf),ADL 的引入是否可以被阻止?

Why was argument dependent lookup (ADL) invented? Is it just so we can write cout << stuff instead of std::operator<<(cout, stuff)? If that is the case, why wasn't ADL limited to operators instead of all functions?

Could the introduction of ADL have been prevented if C++ had had some other way to do generic output of both built-in and user-defined types, for example a type-safe printf via variadic templates?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

硬不硬你别怂 2024-10-11 00:45:35

ADL 的发明是为了允许接口原则:

接口原则

对于类 X,所有函数,包括自由函数,都

  • “提及”X,并且
  • “提供” “ X

在逻辑上是 X 的一部分,因为它们构成了 X 接口的一部分。

查看 Herb Sutter 的优秀文章 关于该主题的本周大师

ADL was invented to allow the Interface Principle:

The Interface Principle

For a class X, all functions, including free functions, that both

  • "mention" X, and
  • are "supplied with" X

are logically part of X, because they form part of the interface of X.

Check out Herb Sutter's excellent Guru of the Week on the topic.

咿呀咿呀哟 2024-10-11 00:45:35

如果是这样,为什么 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< /code> 没有限定其全名。无论如何,ADL 都会找到它。 SeqAn 库过度使用此类命名空间范围的函数,并且为每个用法添加命名空间名称前缀是不切实际的。同样,导入命名空间通常也是不可取的。

当然,许多其他库也是如此,例如大多数 Boost 库。


1 我相信委员会并没有立即意识到这一点。

If that is the case, why wasn't ADL limited to operators instead of all functions?

Why limit it artificially? ADL may be tricky to implement (when combined with C++’ overloading rules)1 but it’s an extremely useful technique. For one thing, the fact that it also works on functions makes it much easier to use other namespaces without importing the whole namespace.

Case in point, the SeqAn library:

using seqan::String;
String<Char> url = "http://www.seqan.de/";
std::cout << "The URL " << url << " has length " << length(url) << std::endl;

Notice that I’ve used the function seqan::length without qualifying its full name. ADL finds it anyway. The SeqAn library uses such namespace-scope functions excessively and prefixing every usage with the namespace name would be impractical. Likewise, importing the namespace often isn’t advisable.

The same is of course true for many other libraries, such as most of Boost’s.


1 And I believe that this wasn’t immediately realized by the committee.

如梦亦如幻 2024-10-11 00:45:35

为什么不将其限制为运算符?

让我们看一个简单的通用算法:

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

正如丹尼尔提到的,这就是萨特所说的接口原则

Why not limit it to operators ?

Let's look at a simple generic algorithm:

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;
}

How does it work with custom types and their own version of swap ? Thanks to ADL.

This is what Sutter calls the Interface Principle, as Daniel mentioned.

半窗疏影 2024-10-11 00:45:35

它的发明是为了允许函数多态性。这个想法是,该功能是一个动词(如“print”),它只有一个含义。根据动词的适用范围(如 int 和 float 和 std::string),仍然可以有不同的实现。

因此,我们需要一个词来描述这个概念,但需要根据它的应用场合有几个实现。

它适用于参数。因此,我们需要一种方法来在多个不同类型的参数上使用相同的单词,并在需要时使用参数类型相对实现。

尝试使用 printInt()、printString()、printFloat() 函数编写复杂的串联,您会看到明显的冗长。

另一个原因是它允许检查给定参数类型的实现是否可用。如果没有可用的实现(甚至没有通用的 - 使用模板),那么编译器会尽快阻止您,并让您知道它没有给定参数的动词的实现。

It was invented to allow function polymorphism. The idea is that the function being a verb (like "print"), it have only one meaning. Still there can be different implementation depending on what the verb apply to (like int and float and std::string).

So we want one word for the concept but several implementation depending on what it's applied to.

What it's applied to is the argument(s). So we needed a way to use the same word on several différent type of arguments with - where needed- argument-type-relative implementation.

Try to write a complex concatenation with printInt(), printString(), printFloat() functions, you'll see the obvious verbosity.

The other reason is that it allows to check wich implementation are available for the givent argument type. If there is no implementation available (not even generic - using templates) then the compiler stop you as soon as he can and makes you know that it don't have an implementation of your verb for the given argument.

温折酒 2024-10-11 00:45:35

是的,它主要是为操作员发明的。但它还使您能够将非成员函数包含到类的接口中。这是一个非常强大的东西,我非常喜欢。这不再局限于运营商。例如,您可能想为您的 vector 类定义一个 cross_product 函数 - 您知道我的意思:)

Yes, it was mostly invented for operators. But it also gives you the ability to incude nonmember functions into the interface of your class. And this is a very powerful thing which I like a lot. And this isn't limited to operators any more. For example, you could want to define a cross_product function for your vector class - you know what I mean :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文