簡體   English   中英

為什么這個函數調用沒有拒絕不合適的重載?

[英]Why is this function call didn't reject the unsuitable overload?

考慮以下代碼:

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

,在命名空間 std 中還有許多其他重載函數,例如:

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::ranges 中的 sort 函子調用是最佳匹配函數,不是嗎? 為什么后來在 std 中發現的這些功能會導致歧義,而不是由於 SFINAE 原則而被放棄?
  2. 如果在我們引入命名空間 std 之后 std 中的函數對於sort(a)是可見的,那么根據a的 ADL,它不應該在第一個代碼中同樣可見嗎?

問題是std::ranges::sort實際上不是函數模板。 它是一些具有特殊名稱查找屬性的可調用實體,有時稱為niebloid 因此,它在名稱查找中的行為不像函數(模板)。

您導入了std::ranges::sortstd::sort以通過通常的非限定名稱查找找到。 std::sort是一個函數(模板),但std::ranges::sort不是。

如果非限定名稱查找找到多個實體並且並非所有實體都是函數或函數模板,則名稱查找不明確並且程序通常格式錯誤。

這就是這里正在發生的事情。

問題是std::ranges::sort被實現為函數對象而不是函數。 名稱查找規則:

對於函數和函數模板名稱,名稱查找可以將多個聲明與同一個名稱相關聯,並且可以從依賴於參數的查找中獲取額外的聲明。 [...]

對於所有其他名稱(變量、命名空間、類等),名稱查找必須生成單個聲明才能編譯程序。

std::ranges::sort是一個變量,因此名稱查找失敗(因為有多個聲明匹配名稱sort )。 並且明確允許將std::ranges算法實現為函數對象(引用std::ranges::sort cppreference ):

本頁描述的類函數實體是niebloids ,即:[...]

在實踐中,它們可以實現為函數對象,或者具有特殊的編譯器擴展。

因此,只要標准庫將std::ranges::sort實現為函數對象(libstdc++ 和 libc++ 似乎都這樣做),如果同時引入std::rangesstd ,就無法進行sort名稱查找在全局命名空間中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM