2013-03-25 76 views
21

如果std::initializer_list中的元素總是常量值,爲什麼我們有模板方法,如begin()/end()而不是cbegin()/cend()?這個名稱(按照慣例,與例如std::vector相比)可能暗示當兩個方法總是返回const_iterator時,兩個方法都可以返回iteratorstd :: initializer_list沒有cbegin()/ cend()

+2

一個很好的問題。做得好。 – 2013-03-25 20:20:15

+0

@LightnessRacesinOrbit嘿美女,很高興在這裏見到你:-) – Des1gnWizard 2016-01-07 08:57:59

+0

@ Des1gnWizard:這不是一個交友網站,謝謝。 – 2016-01-07 10:49:05

回答

25

雖然我不能提供關於原因的見解,爲什麼cbegin()cend()std::initializer_list「s接口另外的一部分begin()end(),一定會有很好的理由,最後兩個成員函數應該是那裏。

的一個原因是,例如,該基於範圍的for環由C++ 11標準精確地在功能begin()end()(段落6.5.4/1)來定義。因此,爲了使其能夠與初始化列表使用它,std::initializer_list必須提供begin()end()成員函數:

#include <utility> 
#include <iostream> 

int main() 
{ 
    auto l = { 1, 2, 3, 4, 5 }; 
    for (int x : l) // Works because std::initializer_list provides 
        // the member functions begin() and end(). 
    { 
     std::cout << x << " "; 
    } 
} 

而且,是有意義的考慮成員函數cbegin()cend()不存在前因此,在std::initializer_list的接口上具有begin()end()允許根據begin()end()編寫的舊通用算法也可以使用初始化器列表,而不需要它們被重寫。

你寫:

這些名字(按約定,比較例如std::vector)可能表明,這兩個std::initializer_list方法可以返回iterator,當他們總是返回const_iterator

其實這個比喻不是很合適。 std::vector的功能begin(),例如,對std::vectorconst實例調用時(即,可變的一個,它的元素可以被修改,添加和刪除)返回一個iterator,並且當上一個const實例調用一個const_iterator(即一個不變的一個,其內容不能被修改):

#include <vector> 
#include <type_traits> 

int main() 
{ 
    // A non-const vector... 
    std::vector<int> v = { 1, 2, 3, 4, 5 }; 

    auto i = v.begin(); 
    static_assert(
     std::is_same<decltype(i), decltype(v)::iterator>::value, 
     //          ^^^^^^^^ 
     //          ...non-const iterator! 
     "What?"); 

    // A const vector... 
    std::vector<int> const vc = { 1, 2, 3, 4, 5 }; 
    auto ic = vc.begin(); 
    static_assert(
     std::is_same<decltype(ic), decltype(vc)::const_iterator>::value, 
     //          ^^^^^^^^^^^^^^ 
     //          ...const iterator! 
     "What?"); 
} 

初始化列表被定義不可改變的集合。每一段中的C++ 11標準的18.9/2:

initializer_list<E>類型的對象提供了訪問const E類型的對象的陣列。 [...]

因爲初始化列表是const元素的集合,該cbegin()cend()功能實際上會做同樣的事情,begin()end()做。

事實上,iteratorconst_iterator都被定義爲指針初始化列表中的值類型的常量元素,所以這是值得商榷無論是begin()end()總是返回const_iterator(如你認爲),還是他們總是這樣返回iterator

這是標準如何段落的C++ 11 18.9/1定義了initializer_list類模板:

namespace std { 
    template<class E> class initializer_list { 
    public: 
     typedef E value_type; 
     // ... 
     typedef const E* iterator; 
     typedef const E* const_iterator; 
     // ... 
     constexpr const E* begin() const noexcept; // first element 
     constexpr const E* end() const noexcept; // one past the last element 
    }; 

    // ... 
} 
+6

我記得當我曾經在SO上獲得代表權時,但是後來有人來了,並以優秀的形式回答了所有優秀的C++問題。現在我只能投票。 +1 – GManNickG 2013-03-25 20:22:08

+0

@GManNickG:我很受寵,儘管我相信你比我更值得稱讚,但我很高興能得到你的支持。謝謝。 – 2013-03-25 20:25:56

+2

@GManNickG:想想看所有從第1天起就被JonSkeeted的C#人員。 – MSalters 2013-03-26 13:33:56

相關問題