为什么这个函数调用没有拒绝不合适的重载?

zcl*_*lll 2 c++ overloading sfinae overload-resolution argument-dependent-lookup

考虑以下代码:

#include<vector>
#include<ranges>
#include<algorithm>
//using namespace std;
using namespace std::ranges;
int main()
{
    std::vector<int> a = {};
    sort(a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它运行正常。

显然,它调用了这个重载函数(函子,严格来说):

template<random_access_range _Range,
     typename _Comp = ranges::less, typename _Proj = identity>
  requires sortable<iterator_t<_Range>, _Comp, _Proj>
  constexpr borrowed_iterator_t<_Range>
  operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
  {
return (*this)(ranges::begin(__r), ranges::end(__r),
           std::move(__comp), std::move(__proj));
  }
Run Code Online (Sandbox Code Playgroud)

但是在我们引入命名空间 std 后,函数调用变得不明确(出现编译错误):

#include<vector>
#include<ranges>
#include<algorithm>
using namespace std;
using namespace std::ranges;
int main()
{
    std::vector<int> a = {};
    sort(a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

除了之前的重装之外

 2045 |   inline constexpr __sort_fn sort{};
Run Code Online (Sandbox Code Playgroud)

,在命名空间 std 中还发现了许多其他重载函数,例如:

template<class _ExecutionPolicy, class _RandomAccessIterator> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> std::sort(_ExecutionPolicy&&, _RandomAccessIterator, _RandomAccessIterator)
Run Code Online (Sandbox Code Playgroud)

template<class _RAIter, class _Compare> constexpr void std::sort(_RAIter, _RAIter, _Compare)
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. std::ranges 中排序函子的调用是最佳匹配函数,不是吗?为什么后来在std中发现的这些函数会导致歧义,而不是因为SFINAE原则而被放弃?
  2. 如果 std 中的函数在我们引入命名空间 std 后可见sort(a),那么根据 的 ADL,它在第一个代码中不应该同样可见吗a

use*_*522 5

问题是这std::ranges::sort实际上并不是一个函数模板。它是一些具有特殊名称查找属性的可调用实体,有时称为niebloid。因此,它在名称查找中的行为不像函数(模板)。

您导入了两者std::ranges::sort,并std::sort可以通过通常的非限定名称查找找到。std::sort是一个函数(模板),但std::ranges::sort不是。

如果非限定名称查找找到多个实体,并且并非所有实体都是函数或函数模板,则名称查找不明确,并且程序通常格式错误。

这就是这里正在发生的事情。