对于类型为 class 模板专业化的参数,ADL 背后的基本原理是什么

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

我花了一些时间试图了解为什么我的代码无法编译并且我已经意识到在 C++ 中 Argument Dependent Lookup 使用模板类型名参数来确定名称查找范围。

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

因此前一个 ref 调用编译,因为对于 myns::X<int> 只考虑 myns::ref,而后者不编译,因为它找到 myns::ref() 以及 std::ref

我的问题是这有什么用?我为什么需要这个?你有什么想法,例子吗?现在我只能看到上面例子中的缺点,它引入了不必要的歧义。

假设你把所有的东西都放到你自己的命名空间里,包括一个用户定义的class,和一个以std::vector为参数的函数。即

namespace myns {

    struct X {};

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

} // namespace myns

那么你可以利用 ADL 也会考虑作为模板参数提供的类型这一事实,只需编写:

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

另一方面:

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

回到你原来的问题,这里的教训是不要使用标准库中的名称,它只会使代码混乱。

一言以蔽之:重用。它允许您使用来自其他库的有用组件,并且仍然应用了 ADL。

例如:

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

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

现在您可以自然地编写代码,就像直接使用 class 一样:

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

如果不是这种情况,您需要在自己的命名空间中推出自己的智能指针,以促进良好的编码习惯用法和 ADL。