2013-03-25 118 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

相关问题