为什么此功能调用不拒绝不合适的过载?

发布于 2025-02-08 15:42:14 字数 1689 浏览 1 评论 0原文

考虑以下代码:

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

它运行正常。

显然,它称之为此过载函数(严格地说):

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));
  }

但是,在我们介绍了名称空间std之后,函数调用变得模棱两可(获得编译错误):

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

除了先前的重新加载

 2045 |   inline constexpr __sort_fn sort{};

,还有许多其他过载函数就像:

template<class _ExecutionPolicy, class _RandomAccessIterator> __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, void> std::sort(_ExecutionPolicy&&, _RandomAccessIterator, _RandomAccessIterator)

所以

template<class _RAIter, class _Compare> constexpr void std::sort(_RAIter, _RAIter, _Compare)

我的问题是:

  1. std ::范围中排序函数的呼唤是最好的匹配功能,不是吗?为什么后来在STD中发现的这些功能会引起歧义,而不是由于Sfinae原则而被放弃?
  2. 如果sort(a)在我们引入命名空间std后可以看到std中的功能,那么根据a的ADL,在第一个代码中不应该同样可见。 ?

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:

  1. The call of sort functor in std::ranges is the best match function, isn't it? Why do these functions later found in std cause ambiguity, rather than being abandoned due to the SFINAE principle?
  2. If the functions in std are visible for sort(a) after we introduced the namespace std, shouldn't it be equally visible in the first code according to the ADL of a?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梨涡 2025-02-15 15:42:14

问题是std :: ranges :: Sort实际上不是函数模板。它是一些具有特殊名称查找属性的可叫实体,有时称为a niebloid 。结果,它的行为不像名称查找中的函数(模板)。

您将两个std :: Ranges :: Sortstd :: sort以通常的不合格的名称查找找到。 std :: sort是一个函数(模板),但是std :: ranges :: sort不是。

如果不合格的名称查找找到了多个实体,而不是所有实体都是函数或功能模板,则名称查找模棱两可,并且程序通常不构建。

那就是这里发生的事情。

The problem is that std::ranges::sort is not actually a function template. It is some callable entity with special name lookup properties, sometimes called a niebloid. As a consequence it doesn't behave like a function (template) in name lookup.

You imported both std::ranges::sort and std::sort to be found by usual unqualified name lookup. std::sort is a function (template), but std::ranges::sort isn't.

If unqualified name lookup finds multiple entities and not all of them are functions or function templates, then the name lookup is ambiguous and the program usually ill-formed.

That is what is happening here.

霊感 2025-02-15 15:42:14

问题是std :: ranges :: Sort是作为函数对象而不是函数实现的。来自 name lookup 规则:

对于函数和功能模板名称,名称查找可以将多个声明与相同名称相关联,并且可以从与参数有关的查找中获取其他声明。 [...]

对于所有其他名称(变量,名称空间,类等),名称查找必须产生单个声明才能使程序编译。

std :: Ranges :: Sort是一个变量,因此名称查找失败(因为有多个声明匹配名称sort)。和std :: ranges算法被明确实现为函数对象(引用 std :: ranges :: sort cppReference ):

此页面上描述的类似功能的实体是 niebloids ,即:[...]

实际上,它们可以作为函数对象或特殊编译器扩展。

实现。

因此,只要标准库实施std :: ranges :: sort作为函数对象(以及libstdc ++和libc ++似乎都这样做),就无法制作sort name Lookup工作,如果您在全局名称空间中介绍了std :: rangesstd

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文