如何在C++17中为自定义包装类实现迭代器遍历
问题解答
一、基础遍历的实现方式
要让Wrapper支持begin()/end()遍历,直接转发底层容器的迭代器即可,代码如下:
class Wrapper { public: Wrapper() = default; std::vector<int> vec; // 非const版本迭代器,供非const对象使用 auto begin() noexcept { return vec.begin(); } auto end() noexcept { return vec.end(); } // const版本迭代器,供const对象使用 auto begin() const noexcept { return vec.begin(); } auto end() const noexcept { return vec.end(); } };
此时你就能像示例中那样用std::for_each或者范围for循环遍历Wrapper实例。
二、最小实现要求
如果只需要支持最基础的正向遍历(比如std::for_each、范围for),仅需实现四个成员函数:
- 非const的
begin()和end() - const的
begin()和end()
这四个函数是让类符合可迭代范围的最小要求,C++17的标准算法只要拿到合法的迭代器对就能正常工作。
三、适配所有标准算法的完整实现
要让Wrapper完全适配所有标准库算法,需要补充以下内容:
1. 反向迭代器支持
实现rbegin()/rend()的非const和const版本,支持std::reverse这类反向遍历的算法:
auto rbegin() noexcept { return vec.rbegin(); } auto rend() noexcept { return vec.rend(); } auto rbegin() const noexcept { return vec.rbegin(); } auto rend() const noexcept { return vec.rend(); }
2. 迭代器关联类型定义
虽然C++17的auto返回值能让编译器推导迭代器类型,但为了适配依赖容器关联类型的模板代码,最好在Wrapper内定义和底层容器一致的关联类型:
class Wrapper { public: using value_type = typename std::vector<int>::value_type; using reference = typename std::vector<int>::reference; using const_reference = typename std::vector<int>::const_reference; using iterator = typename std::vector<int>::iterator; using const_iterator = typename std::vector<int>::const_iterator; using reverse_iterator = typename std::vector<int>::reverse_iterator; using const_reverse_iterator = typename std::vector<int>::const_reverse_iterator; using size_type = typename std::vector<int>::size_type; using difference_type = typename std::vector<int>::difference_type; // ... 其他成员函数 ... };
3. 容器属性相关成员函数
补充这些函数以支持需要容器元信息的算法:
size_type size() const noexcept { return vec.size(); } bool empty() const noexcept { return vec.empty(); } int* data() noexcept { return vec.data(); } const int* data() const noexcept { return vec.data(); }
其中size()支持std::fill_n这类需要长度的算法,empty()供很多算法做前置检查,data()支持直接内存访问的优化版算法(比如std::copy)。
4. 可选扩展接口
如果需要支持更完整的容器操作(比如插入、删除元素),可以继续转发底层容器的成员函数,比如push_back()、insert()、erase()等,但这不属于适配标准算法的强制要求,仅用于扩展类功能。
四、通用封装扩展(可选)
如果想让Wrapper能封装任意标准容器(不限于std::vector<int>),可以改成模板类:
template <typename Container = std::vector<int>> class Wrapper { public: using container_type = Container; using value_type = typename Container::value_type; using reference = typename Container::reference; using const_reference = typename Container::const_reference; using iterator = typename Container::iterator; using const_iterator = typename Container::const_iterator; using reverse_iterator = typename Container::reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; using size_type = typename Container::size_type; using difference_type = typename Container::difference_type; Wrapper() = default; Container cont; auto begin() noexcept { return cont.begin(); } auto end() noexcept { return cont.end(); } auto begin() const noexcept { return cont.begin(); } auto end() const noexcept { return cont.end(); } auto rbegin() noexcept { return cont.rbegin(); } auto rend() noexcept { return cont.rend(); } auto rbegin() const noexcept { return cont.rbegin(); } auto rend() const noexcept { return cont.rend(); } size_type size() const noexcept { return cont.size(); } bool empty() const noexcept { return cont.empty(); } auto data() noexcept { return cont.data(); } auto data() const noexcept { return cont.data(); } };
这样Wrapper就可以封装std::list、std::deque等任意标准容器。
内容的提问来源于stack exchange,提问作者TheMemeMachine
相关产品推荐
相关产品推荐

