如果std::initializer_list
中的元素始终是const值,为什么我们有begin()/end()
而不是cbegin()/cend()
等模板方法?这些名称(根据惯例,与std::vector
进行比较)可能表明std::initializer_list
方法在返回iterator
时都会返回const_iterator
。
答案 0 :(得分:25)
虽然除了 {{{{}}之外,我无法提供cbegin()
和cend()
不属于std::initializer_list
的界面的原因的见解1}}和begin()
,最后两个成员函数应该存在的原因当然有很好的理由。
例如,一个原因是基于范围的end()
循环是由C ++ 11标准精确定义的函数for
和begin()
(第6.5段)。 4/1)。因此,为了能够将其与初始值设定项列表一起使用,end()
必须提供std::initializer_list
和begin()
成员函数:
end()
此外,考虑在C ++ 11之前不存在成员函数#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()
和begin()
end()
允许使用std::initializer_list
和begin()
编写的旧通用算法也可以使用初始化列表,而不需要重写它们。
你写道:
这些名称(根据惯例,与
end()
进行比较)可能表明std::vector
方法在返回std::initializer_list
时都会返回iterator
。
实际上,这个类比并不合适。例如,const_iterator
的函数std::vector
在begin()
的非iterator
实例上调用时返回const
(即一个可变的实例,其元素可以修改,添加和删除),并在std::vector
实例上调用const_iterator
(即不可更改的实例,其内容不能更改):
const
根据定义,初始化程序列表是不可变集合。根据C ++ 11标准的第18.9 / 2段:
类型为
#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?"); }
的对象提供对initializer_list<E>
类型对象数组的访问。 [...]
由于初始化列表是const E
个元素的集合,const
和cbegin()
函数实际上与cend()
和begin()
完全相同。
实际上,end()
和iterator
都被定义为指向初始化列表的值类型的常量元素的指针,因此可以说是const_iterator
和{{1}的情况总是返回begin()
(如您所愿),或者它们是否总是返回end()
。
这就是C ++ 11标准的第18.9 / 1段如何定义const_iterator
类模板:
iterator