23

如果元素std::initializer_list总是 const 值,为什么我们有模板方法 likebegin()/end()和 not cbegin()/cend()?这个名称(按照惯例,与 eg 相比std::vector)可能表明这两种std::initializer_list方法都可以 return iterator,而它们总是 return const_iterator

4

1 回答 1

26

虽然我无法解释为什么cbegin()andcend()不是除了andstd::initializer_list的接口的一部分的原因,但肯定有充分的理由说明最后两个成员函数应该在那里。 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()在 C++11 之前不存在是有意义的:因此,在 的接口上具有begin()和允许使旧的泛型算法根据初始值设定项列表编写和工作,而不需要它们是重写。end()std::initializer_listbegin()end()

你写:

这些名称(按照惯例,与 eg 相比std::vector)可能表明这两种std::initializer_list方法都可以 return iterator,而它们总是 return const_iterator

其实这个比喻不太恰当。std::vector的函数begin(),例如,iterator在非const实例std::vector(即可变实例,其元素可以修改、添加和删除)上const_iterator调用时返回一个,在实例上调用时返回一个const(即不可变实例,其内容不能更改):

#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()and函数实际上会做与andcend()完全相同的事情。begin()end()

实际上,iteratorandconst_iterator都被定义为指向初始化器列表值类型的常量元素的指针,因此有争议的是,begin()andend()总是 return const_iterator(如你所假设),或者它们是否总是 return 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
    };

    // ...
}
于 2013-03-25T20:10:59.410 回答