为何无法对std::array::end()执行递减操作?
为啥
--arr.end()报错,--vec.end()却没事? 嗨,这个问题我之前也踩过坑!本质是两种容器的迭代器类型不一样导致的——你的编译器里,std::array用的是原生指针当迭代器,而std::vector的迭代器是个类模板对象。
咱们掰碎了说:
- 原生指针的前置递减
--要求操作数是左值(就是能被赋值的东西),因为它要直接修改这个指针的值。但arr.end()返回的是个临时的指针(右值),你没法直接对一个临时的右值指针做--操作,所以编译器就炸了,报那个lvalue required as decrement operand的错。 - 而
vector的迭代器如果是类类型的话,情况就不同了:类的operator--()成员函数可以被临时对象(右值)调用(只要这个函数没被限定只能左值用)。当你对vec.end()返回的临时迭代器调用--时,它会修改这个临时对象,然后返回引用,所以--vec.end()就能正常工作。
那怎么解决这个兼容问题?给你几个通用方案,不管是array还是vector都能用:
- 先把end迭代器存成左值,再递减:
auto arr_end = arr.end(); auto arr_it = --arr_end; // 这样就没问题了,arr_end是左值
- 用C++11引入的
std::prev函数,这是最优雅的方式,专门用来获取前一个迭代器:
auto arr_it = std::prev(arr.end()); // 不管是指针还是类迭代器都能完美适配
- 要是还在用C++03,也可以直接用
arr.end() - 1(因为array和vector的迭代器都是随机访问迭代器,支持减法):
auto arr_it = arr.end() - 1;
回到你的display()模板函数,推荐用std::prev来替换直接--cont.cend()的写法,这样就能兼容所有随机访问迭代器的容器了:
#include <iterator> // 要包含这个头文件用std::prev template <typename Container> void display(const Container& cont) { for (auto it = cont.cbegin(); it != cont.cend(); ++it) { if (it != std::prev(cont.cend())) { std::cout << *it << ", "; } else { std::cout << *it; } } std::cout << '\n'; }
另外,还有个更简洁的写法可以避免判断最后一个元素——先输出第一个元素,然后剩下的元素前面加逗号:
template <typename Container> void display(const Container& cont) { if (cont.empty()) return; auto it = cont.cbegin(); std::cout << *it; for (++it; it != cont.cend(); ++it) { std::cout << ", " << *it; } std::cout << '\n'; }
内容的提问来源于stack exchange,提问作者Jersey
相关产品推荐
相关产品推荐

