Why was argument dependent lookup invented?

帅比萌擦擦* 提交于 2019-12-09 03:02:26

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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.




回答5:


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 :)



来源:https://stackoverflow.com/questions/4276772/why-was-argument-dependent-lookup-invented

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!