既然有了cbegin(), cend(),为什么没有cfront(), cback(), cfind(),…
Given cbegin(), cend(), why is there no cfront(), cback(), cfind(), ...?
所以,为了允许像
这样的代码auto vect = ...;
auto it = vect.begin(), end = vect.end(); // want const_iterator, getting iterator
选择正确的begin()
和end()
的重载,即使对于非const容器,也添加了更显式的cbegin()
/cend()
函数。
为什么到此为止?
关联容器有一个find()
方法也有同样的问题。序列容器有front()
和back()
,同样有同样的问题。
这些缺失的显式const版本是省略的,还是故意的?
一个更广泛的API是有成本的,甚至只是在寻找你想要的函数时跳过它。
template<class T>
T const as_const(T&& t) noexcept(noexcept(T(std::declval<T>())) {
return std::forward<T>(t);
}
template<class T>
T const& as_const(T& t) noexcept {
return t;
}
做了大部分你想做的。它甚至会使cbegin
过时。
(根据下面@ tc提供的n4380对上面代码所做的修改)。代码不同,因为我认为n4380在T&&
的情况下略有错误。)
cbegin
/cend
的目的是解决一个特定的问题。考虑以下代码:
std::vector<int> & v = //... v is a non-const reference
// For clarity, I want this iterator to be a const_iterator.
// This works because iterator is implicitly convertible to const_iterator
std::vector<int>::const_iterator iter = find(v.begin(),v.end(),42);
// (1) Now I want to use iter in an algorithm
std::find(iter, v.end(), 38); //Error, can not deduce the template parameter for Iter.
// (2) This works
std::find(iter, const_cast<const std::vector<int> &>(v).end(), 38);
// (3) This is the same as (2).
std::find(iter, v.cend(), 38);
问题是,由于模板推导规则的工作方式,编译器无法推导语句(1)中的模板迭代器参数,因为Container::iterator
和Container::const_iterator
(可能)是两种完全不相关的类型(即使前者在后者中可以隐式转换)。
语句(2)不完全是一个漂亮的行,这就是为什么我们需要 cend()
。
现在,front()
, back()
等都返回一个引用。非const引用总是可以在模板化函数中推导为const,即:
template<class T> void f( const T & l, const T & r);
int main()
{
int x; vector<int> v;
//This will works even if the return type of front() is int&.
f(x, v.front());
}
因为标准要求Container::const_reference
等于const Container::value_type &
,所以cfront()
/cback()
不给我们买任何东西。
值得一提的是,其他容器库(看看你的Qt)是使用写时复制实现的。
这意味着在这样的容器上调用const函数可能比调用等效的非const版本要便宜得多,因为非const可能会复制整个容器的底层。
由于这个原因,Qt容器在其接口中有很多constFunction
,用户可以自由选择正确的