簡體   English   中英

為什么std :: cbegin()不會在容器上調用.cbegin()?

[英]Why does std::cbegin() not call .cbegin() on the container?

以下代碼未通過靜態斷言:

#include <gsl/span>
#include <iterator>
#include <type_traits>

int main()
{
    int theArr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    gsl::span<int> theSpan{ theArr, std::size(theArr) };

    using std::cbegin;
    auto it1 = cbegin(theSpan);
    auto it2 = theSpan.cbegin();
    static_assert(std::is_same_v<decltype(it1), decltype(it2)>);
}

這失敗是因為std::cbegin()在容器的const ref上調用.begin()方法。 對於標准定義的容器,這將返回一個const_iterator ,它與.cbegin()返回的類型相同。 但是, gsl::span有點獨特,因為它模擬了一種“借用類型”。 const gsl::span行為類似於const指針; span本身是const,但它指向的不是const。 因此, const gsl::span上的.begin()方法仍然返回一個非const迭代器,而顯式調用.cbegin()返回一個const迭代器。

我很好奇為什么std::cbegin()沒有被定義為在容器上調用.cbegin() (所有標准容器似乎都要實現)來解決這種情況。

這與以下內容有些相關: 為什么std :: cbegin返回與std :: begin相同的類型

這失敗,因為std::cbegin()調用.begin()

更確切地說, std::cbegin調用std::begin ,它在泛型重載中調用c.begin

對於它的價值,應該可以修復gsl::span以在std::cbegin上返回const迭代器,如果gsl的設計者指定對於gsl::spanstd::cbegin的泛型重載有一個特殊化,那么如果這是所需的行為,則使用c.cbegin而不是std::begin 我不知道他們沒有指定這種專業化的理由。

至於為什么std::cbegin使用std::begin ,我也不知道,但它確實具有能夠支持具有c.begin成員但不是c.cbegin成員的容器的優點。 ,可以看作是一個不太嚴格的要求,因為它可以通過在C ++ 11之前編寫的自定義容器來滿足,當時沒有提供c.cbegin成員函數的約定。

首先,請注意,根據[tab:container.req]

表達式: a.cbegin()

返回類型: const_iterator

操作語義: const_cast<​X const&​>(a)​.begin();

復雜性:不變

因此, gsl::span根本不是容器。 cbegincend被設計成集裝箱的工作。 有一些例外(數組, initializer_list )需要特別小心,但顯然標准庫不能提到像gsl::span這樣的東西。

其次,它是LWG 2128介紹了全球cbegincend 讓我們看看相關部分的內容:

通過調用std::begin/end()實現std::cbegin/cend() std::begin/end() 這有很多好處:

  • 它自動適用於數組,這是這些非成員函數的重點。

  • 它適用於在cbegin/cend()成員發明之前編寫的C ++ cbegin/cend()時代用戶容器。

  • 它適用於initializer_list ,它非常小,缺少cbegin/cend()成員。

  • [container.requirements.general]保證這相當於調用cbegin/cend()成員。

本質上,調用std::begin/end()節省為數組和initializer_list提供特殊維護的工作。

暫無
暫無

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

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