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

开头

    之前写了部分关于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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值