Consider the following code:
#include<vector>
#include<ranges>
#include<algorithm>
//using namespace std;
using namespace std::ranges;
int main()
{
std::vector<int> a = {};
sort(a);
return 0;
}
It's running properly.
Obviously, it called this overload function(functor, strictly speaking):
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));
}
But after we introducing the namespace std, the function call became ambiguous(got compilation errors):
#include<vector>
#include<ranges>
#include<algorithm>
using namespace std;
using namespace std::ranges;
int main()
{
std::vector<int> a = {};
sort(a);
return 0;
}
In addition to the previous reloads
2045 | inline constexpr __sort_fn sort{};
, there are many other overload functions found in namespace std like:
template<class _ExecutionPolicy, class _RandomAccessIterator> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> std::sort(_ExecutionPolicy&&, _RandomAccessIterator, _RandomAccessIterator)
and
template<class _RAIter, class _Compare> constexpr void std::sort(_RAIter, _RAIter, _Compare)
So my questions are:
sort(a)
after we introduced the namespace std, shouldn't it be equally visible in the first code according to the ADL of a
?The problem is that std::ranges::sort
is implemented as function object and not a function. From name lookup rules:
For function and function template names, name lookup can associate multiple declarations with the same name, and may obtain additional declarations from argument-dependent lookup. [...]
For all other names (variables, namespaces, classes, etc), name lookup must produce a single declaration in order for the program to compile.
std::ranges::sort
is a variable, and thus name lookup fails (because there is more than one declaration matching name sort
). And std::ranges
algorithms are explicitly allowed to be implemented as function objects (quote from std::ranges::sort
cppreference):
The function-like entities described on this page are niebloids, that is: [...]
In practice, they may be implemented as function objects, or with special compiler extensions.
So, as long as standard library implements std::ranges::sort
as function object (and both libstdc++ and libc++ seem to do that), there is no way to make sort
name lookup work if you introduce both std::ranges
and std
in global namespace.