深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-2.自己实现一个支持范围for循环的类~

来源:互联网 发布:3ds数据搬家 编辑:程序博客网 时间:2024/06/01 07:36

开头

    之前写了部分关于c++11让程序更简洁相关内容,至于分出来第二部分,是由于之前都展示的一些纯语法相关并未主动编写代码,这里有一个需要编写一些代码的,所以单独摘出来。

让基于范围的for循环(支持自定义类型)

如何让基于范围的for循环运转

具体来说,基于范围的for循环只是普通for循环的语法糖,它需要查找容器的begin和end迭代器。
1. 对于普通array对象,begin将为array首地址,end为首地址加容器长度;
2. 容器是类对象,range-based for将试图通过查找类的begin()和end()定位;
3. 其他,通过全局begin和end定位。

实现对区间的迭代

namespace detail_range {    template<typename T>    class iterator     {    public:        using value_type = T;        using size_type = size_t;    private:        size_type cursor_;        const value_type step_;        value_type value_;    public:        iterator(size_type cur_start, value_type begin_val, value_type step_val)             : cursor_(cur_start), step_(step_val), value_(begin_val)        {            value_ += (step_ * cursor_);        }        value_type operator*() const { return value_; }        bool operator!=(const iterator& rhs) const        {            return cursor_ != rhs.cursor_;        }        iterator& operator++()        {            value_ += step_;            ++cursor_;            return *this;        }    };    template<typename T>    class impl    {    public:        using value_type    = T;        using reference     = value_type&;        using const_reference = const value_type&;        using iterator = detail_range::iterator<value_type>;        using const_iterator = const detail_range::iterator<value_type>;        using size_type = typename iterator::size_type;    private:        const value_type begin_;        const value_type end_;        const value_type step_;        const size_type max_count_;        size_type get_adjusted_count() const        {            if (step_ > 0 && begin_ >= end_) {                throw std::logic_error("when step > 0, end value must be greater than begin value");            } else if (step_ < 0 && begin_ <= end_) {                throw std::logic_error("when step < 0, end value must be smaller than begin value");            }            size_type count = static_cast<size_type>((end_ - begin_) / step_);            if (begin_ + (step_ * count) != end_) {                ++count;            }            return count;        }    public:        impl(value_type begin_val, value_type end_val, value_type step_val)            : begin_(begin_val)            , end_(end_val)            , step_(step_val)            , max_count_(get_adjusted_count())        {}        size_type size() const        {            return max_count_;        }        const_iterator begin() const {            return{0, begin_, step_ };        }        const_iterator end() const {            return{ max_count_, begin_, step_ };        }    };    template<typename T>    impl<T> range(T end) {        return{ {0}, end, 1 };    }    template<typename T>    impl<T> range(T begin, T end) {        return{ begin, end, 1 };    }    template<typename T, typename U>    auto range(T begin, T end, U step)->impl<decltype(begin + step)> {        using r_t = impl<decltype(begin + step)>;        return r_t( begin, end, step );    }}

使用:

int main(){    for (auto i : detail_range::range(5, 20, 0.5)) {        cout << i << endl;    }}

以上代码主要摘抄书中的例子,有几点觉得书中写得很好:

  1. 实现impl中将类型进行了统一,避免了impl中的一些不必要的复杂度,然后在rang中将step和begin类型进行统一;
  2. using r_t = impl

尝试自己改造一个rang,支持从标准容器中间隔取值

附上代码吧,还缺少一些出错判断但能满足一般需求,待真实使用中进一步改进:

#pragma once#include <assert.h>namespace container_range {    template<typename T>    class iterator    {    public:        using iterator_type = T;        using size_type = size_t;        using value_type = typename iterator_type::value_type;    private:        iterator_type cursor_;        iterator_type end_;        const int step_;    public:        iterator(iterator_type cur_start, iterator_type cur_end, int step_val)            : cursor_(cur_start), end_(cur_end), step_(step_val)        {            assert(step_ >= 0);        }        value_type operator*() const { return *cursor_; }        bool operator!=(const iterator& rhs) const        {            return cursor_ != rhs.cursor_;        }        iterator& operator++()        {                       auto diff = std::distance(cursor_, end_);            assert(diff >= 0);            if (step_ < diff) {                std::advance(cursor_, step_);            }            else {                cursor_ = end_;            }            return *this;        }    };    template<typename ContainerT>    class impl{    public:        using container_type = ContainerT;        using value_type = typename ContainerT::value_type;        using const_reference = typename ContainerT::const_reference;        using container_iterator_type = decltype(ContainerT().begin());    private:        ContainerT container_;        int step_;        int begin_;    public:        impl(ContainerT container, int begin, int step) : container_(container), begin_(begin), step_(step) {}        iterator<container_iterator_type> begin() {            auto beginIt = container_.begin();            std::advance(beginIt, begin_);            return{ beginIt, container_.end(), step_};        }        iterator<container_iterator_type> end() {            return{ container_.end(), container_.end(), step_};        }    };    template<typename ContainerT>    impl<ContainerT> range(ContainerT container, int begin, int step) {        return{container, begin, step};    }}

下面是使用例子:

#include <iostream>#include "containerRange.h"#include <list>int main(){    std::list<int>  l = {1, 2, 3, 4, 5, 6, 7};    for (auto i : container_range::range(l, 0, 2)) { //  从第一个1个元素开始取,间隔为2        std::cout << i << std::endl;    }    int v = 0;    std::cin >> v;    return 0;}

输出结果如下,满足初始设计要求。
1
3
5
7

0 0
原创粉丝点击