What is the rationale behind ADL for arguments whose type is a class template specialization
Asked Answered
T

2

10

I've spent some time trying to realize why my code doesn't compile and I've realized that in C++ Argument Dependent Lookup uses template typename arguments to determine name lookup scope.

#include <string>
#include <functional>

namespace myns {

    template<typename T>
    struct X
    {};

    template<typename T>
    auto ref(T) -> void
    {}

} // namespace myns

auto main() -> int
{
    ref(myns::X<int>{});
    ref(myns::X<std::string>{}); // error: call to 'ref' is ambiguous
}

So the former ref call compiles, because for myns::X<int> only myns::ref is considered, while the latter doesn't compile because it finds myns::ref() as well as std::ref

My question is how this can be useful? Why would I need this? Do you have any ideas, examples? For now I can only see drawbacks like in the example above, where it introduces unneeded ambiguity.

Titanesque answered 19/4, 2017 at 10:21 Comment(2)
Do you need your function to accept any type? Otherwise auto ref(X<T>) -> void would be a better match than std::ref and be selected by the overload resolution.Gallous
Unfortunately yes, I do.Titanesque
U
7

Suppose you put all the things into your own namespace, including a user-defined class, and a function which takes std::vector as the parameter. i.e.

namespace myns {

    struct X {};

    template<typename T>
    auto my_func(const std::vector<T>&) -> void
    {}

} // namespace myns

then you can take advantage of the fact that ADL also considers the types provided as template arguments and just write:

my_func(std::vector<myns::X>{});

on the other hand:

my_func(std::vector<int>{});        // error, can't find my_func
myns::my_func(std::vector<int>{});  // fine

Get back to your original question, the lesson here is don't use names from standard libraries, it just makes codes confusing.

Uella answered 19/4, 2017 at 10:36 Comment(0)
M
3

In one word: reuse. It allows you to use useful components from other libraries, and still have ADL applied.

For instance:

namespace my_stuff {
  class my_class {
    // Something useful here
  };

  void process(std::unique_ptr<my_class> item);
}

Now you can write code naturally, as you would when working with the class directly:

process(std::make_unique<my_class>());

If it wasn't the case, you'd need to roll out your own smart pointer, in your own namespace, just to facilitate good coding idioms and ADL.

Mezzorilievo answered 19/4, 2017 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.