4

When I program in C++, instead of writing using namespace std;, I generally tend to use std:: prefixed components like std::cout, std::cin etc. But then I came across ADL and why you should use using std::swap;.

Many components of the standard library (within std) call swap in an unqualified manner to allow custom overloads for non-fundamental types to be called instead of this generic version: Custom overloads of swap declared in the same namespace as the type for which they are provided get selected through argument-dependent lookup over this generic version.

But in all sources about ADL, they only mention std::swap. Are there any other functions like this that I have to be beware of when using? Or for all other functions should I use fully qualified name? Or should I use unqualified name for every function in std::?

EDIT: (I wasn't clear when phrasing my initial question. Here is what I exactly intended when I was writing the question.)

Is there any other function in C++ standard libraries that is a popular candidate for ADL based customization much like std::swap, so that when I use them, I have to be cautious to use using std::foo; foo(); form instead of invoking std::foo(); directly?

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35
  • 4
    this is only relevant when you write libraries where ADL is a customization point. For non-library code you almost always want to know what is called. – 463035818_is_not_an_ai Jan 16 '23 at 13:00
  • "Should" is a pretty strong word I think. There are no function where the `std::` prefix *should* be left out, but there are functions where it *could* be left out. – Some programmer dude Jan 16 '23 at 13:02
  • 1
    As for functions that *could* be called without the namespace prefix, I often use `std::begin` and `std::end` for standard containers, which thanks to ADL means I leave out the `std::` prefix. But since I sometimes use other containers or iterable objects I have to use either `std::begin` (for example) explicitly or the objects own `begin` member function. This is an inconsistency in my habits that I need to work on I think. :) – Some programmer dude Jan 16 '23 at 13:06
  • 1
    Understanding ADL is an important part of C++. If it isn't understood, mistakes will be made. Much like understanding ASI is an important part of JavaScript, regardless if one is anti-colon or pro-colon. – Eljay Jan 16 '23 at 13:21

1 Answers1

5

Suppose you write a library that works with user supplied types. Then you might want to provide a default implementation to foo a bar. But at the same time you want to enable the user to provide their custom implementation because they might know better how to foo their custom bar.

Thats exactly what happens in the standard library with std::swap. The code that relies on ADL is inside libraries, it works with custom types, types it doesn't know until instantiated. And it can provide a default std::swap but at the same time allows the user to provide their own implementation.

In your user-code, when you know the type, then typically you want to know what function is called. Typically you do know if you want to call my::swap or std::swap and you do not need ADL to choose.

That being said, if you have to ask this quesiton then the answer is: Do not make use of ADL. (I know "If you have to ask.." is somewhat silly, but sometimes is applies just too well). Even in library code you do not always want to enable ADL, or allow it as customization. Even if you do write generic code, there might be situations where you need your way to foo a bar without allowing the user to customize it. It really depends.

Short answer: If you want to call std::swap then call std::swap. If you want to call my::swap then call my::swap. If you want to make use of ADL you will know what to do.


PS: There are more examples of ADL that you know but might not be aware of. You almost never use the std:: prefix when you call an operator overload for example. For example std::string operator+(const std::string&,const std::string&). You could write

 std::string a,b;
 auto c = std::operator+(a,b);

but you don't. You are used to write

 auto c = a + b;

And this only works due to ADL.


PPS: Even for std::swap its not right that it "should not be prefixed with std::". As outlined above, sometimes you do want to make use of ADL and sometimes you don't. That decision is not per function, but per use case. If you write code that swaps two objects and for some reason you want to call std::swap and nothing else, then you call std::swap. If you want to make use of ADL then you make use of ADL.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • If a library provides a better implementation of `swap`, then isn't it always better to use that version? So shouldn't I always make use of ADL when invoking `swap`? – Sourav Kannantha B Jan 16 '23 at 14:22
  • @SouravKannanthaB not sure 100% what you mean. If you are using `thelibrariesnamespace::foo` and there is a `thelibrariesnamespace::swap` to swap `foo`s then probably you should use it, but you do not necessarily need ADL to do that. Hence, no, there is no "should" in using ADL. – 463035818_is_not_an_ai Jan 16 '23 at 14:25
  • 1
    @SouravKannanthaB as I tried to explain, the point of ADL Is that it is a customization point. The generic code does not care if the default `std::swap` is called or the custom `my::swap` is called. If you, in your code decide to use `my::swap` then you do not need ADL. YOu need ADL in generic code when at the time you write the code you cannot know if you call `std::swap` or `someother::swap` – 463035818_is_not_an_ai Jan 16 '23 at 14:27
  • "If there is a `thelibrariesnamespace::swap` to swap `foo`s". This requires me to know the entire list of functions in that library. – Sourav Kannantha B Jan 16 '23 at 14:35
  • Got your point. But suppose, I'm calling a `swap` on an object with no customized `swap` implementation. If I use `std::swap`, then in future, if it provides a customized swap, then I have to edit my code to use it. But instead if I write `using std::swap`, then as soon as I recompile the source, it automatically chooses the new custom implementation. – Sourav Kannantha B Jan 16 '23 at 14:38
  • 2
    @SouravKannathaB yes, you correctly explained the use of ADL. It has downsides too. It can be confusing and unintuitive. Not always you want your code to do something else entirely when some other code has changed. Sometimes you do, sometimes you don't. As I tried to explain, it depends. Its not a "should", but rather "know the consequences then choose" – 463035818_is_not_an_ai Jan 16 '23 at 14:46
  • 1
    "This requires me to know the entire list of functions in that library.:" so what? If you use a library you must read its documentation. A function that swaps a `foo` is part of `foo`s interface and should be documented together with `foo`. – 463035818_is_not_an_ai Jan 16 '23 at 14:47