如果元素std::initializer_list
总是 const 值,为什么我们有模板方法 likebegin()/end()
和 not cbegin()/cend()
?这个名称(按照惯例,与 eg 相比std::vector
)可能表明这两种std::initializer_list
方法都可以 return iterator
,而它们总是 return const_iterator
。
1 回答
虽然我无法解释为什么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_list
begin()
end()
你写:
这些名称(按照惯例,与 eg 相比
std::vector
)可能表明这两种std::initializer_list
方法都可以 returniterator
,而它们总是 returnconst_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()
实际上,iterator
andconst_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
};
// ...
}