Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 464
witosx Avatar asked Apr 19 '17 10:04

witosx


2 Answers

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.

like image 186
songyuanyao Avatar answered Oct 14 '22 08:10

songyuanyao


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.

like image 38
StoryTeller - Unslander Monica Avatar answered Oct 14 '22 08:10

StoryTeller - Unslander Monica