• (原创)用c++11打造类似于python的range


      python中的range函数表示一个连续的有序序列,range使用起来很方便,因为在定义时就隐含了初始化过程,因为只需要给begin()和end()或者仅仅一个end(),就能表示一个连续的序列。还可以指定序列产生的步长,如range(0,10,8)产生的序列为[0, 8], 默认的步长为1,range(3)表示的序列是[0,1,2]。range的遍历也很方便:

    for i in range(3):
        print i

      

      c++11中增加了一项新特性range-based for循环,其实这也不是什么新东西,在c#、java和python等语言中已经有了。这种循环方式非常简洁,它的内部其实是对传统的begin()/end()方式的遍历做了包装,算是一个循环的语法糖。用法很简单:

    //遍历vector
    std::vector<int> v;
    for(auto i : v)
    {
        cout<<i<<endl;
    }
    
    //以只读方式遍历map
    std::map<string, int> map;
    for(const auto& item : map)
    {
        cout << item->first<<item->second<<endl;
    }

      c++11的range-based for循环有意思的地方是他可以支持自定义类型的遍历,但是要求自定义类型满足三个条件:

    1. 要实现begin()和end(),他们分别用来返回第一个和最后一个元素的迭代器;
    2. 提供迭代终止的方法;
    3. 提供遍历range的方法;

    满足这三个条件之后,我们自定义的类型就能支持range-based for循环了。

      再回到刚才提到的python的range(),它很好用,但是c++中目前还没有类似的东西,虽然标准库中有很多容器如vector、list、queue、map、初始化列表和array等等都已经支持了range-based for循环,但是他们使用起来还是不够方便,比如要生成一个有序序列时,需要专门去初始化,如果有一个类似于python range的东西就比较完美了。虽然c++11现在没有,但我们可以自己用c++11去实现一个类似的range,而且我还想让这个range比python的range更强大,让它不仅仅能支持整数还能支持浮点数,同时还能双向迭代,实现这个range还是比较简单的,看看具体实现吧:

    namespace Cosmos
    {
        template<typename value_t>
        class RangeImpl
        {
            class Iterator;
        public:
            RangeImpl(value_t begin, value_t end, value_t step = 1) :m_begin(begin), m_end(end), m_step(step)
            {
                if (step>0&&m_begin >= m_end)
                    throw std::logic_error("end must greater than begin.");
                else if (step<0 && m_begin <= m_end)
                    throw std::logic_error("end must less than begin.");
    
                m_step_end = (m_end - m_begin) / m_step;
                if (m_begin + m_step_end*m_step != m_end)
                {
                    m_step_end++;
                }
            }
    
            Iterator begin()
            {
                return Iterator(0, *this);
            }
    
            Iterator end()
            {
                return Iterator(m_step_end, *this);
            }
    
            value_t operator[](int s)
            {
                return m_begin + s*m_step;
            }
    
            int size()
            {
                return m_step_end;
            }
    
        private:
            value_t m_begin;
            value_t m_end;
            value_t m_step;
            int m_step_end;
    
            class Iterator
            {
            public:
                Iterator(int start, RangeImpl& range) : m_current_step(start), m_range(range)
                {
                    m_current_value = m_range.m_begin + m_current_step*m_range.m_step;
                }
    
                value_t operator*() { return m_current_value; }
    
                const Iterator* operator++()
                {
                    m_current_value += m_range.m_step;
                    m_current_step++;
                    return this;
                }
    
                bool operator==(const Iterator& other)
                {
                    return m_current_step == other.m_current_step;
                }
    
                bool operator!=(const Iterator& other)
                {
                    return m_current_step != other.m_current_step;
                }
    
                const Iterator* operator--()
                {
                    m_current_value -= m_range.m_step;
                    m_current_step--;
                    return this;
                }
    
            private:
                value_t m_current_value;
                int m_current_step;
                RangeImpl& m_range;
            };
        };
    
        template<typename T, typename V>
        auto Range(T begin, T end, V stepsize)->RangeImpl<decltype(begin + end + stepsize)>
        {
            return RangeImpl<decltype(begin + end + stepsize)>(begin, end, stepsize);
        }
    
        template<typename T>
        RangeImpl<T> Range(T begin, T end)
        {
            return RangeImpl<T>(begin, end, 1);
        }
    
        template<typename T>
        RangeImpl<T> Range(T end)
        {
            return RangeImpl<T>(T(), end, 1);
        }
    }

    再看看测试代码:

    void TestRange()
    {
        cout << "Range(15):";
        for (int i : Range(15)){
            cout << " " << i;
        }
        
        cout << endl;
        cout << "Range(2,6):";
        for (int i : Range(2, 6)){
            cout << " " << i;
        }
        cout << endl;
        cout << "Range(10.5, 15.5):";
        for (float i : Range(10.5, 15.5)){
            cout << " " << i;
        }
        cout << endl;
        cout << "Range(35,27,-1):";
        for (int i : Range(35, 27, -1)){
            cout << " " << i;
        }
        cout << endl;
        cout << "Range(2,8,0.5):";
        for (float i : Range(2, 8, 0.5)){
            cout << " " << i;
        }
        cout << endl;
        cout << "Range(8,7,-0.1):";
        for (auto i : Range(8, 7, -0.1)){
            cout << " " << i;
        }
        cout << endl;
    
        cout << "Range('a', 'z'):";
        for (auto i : Range('a', 'z'))
        {
            cout << " " << i;
        }
        cout << endl;
    }

      测试结果:

      可以看到这个range不仅仅会根据步长生成有序序列,还能支持浮点类型和char类型以及双向迭代,比python的range更强大。

      如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。

      c++11 boost技术交流群:296561497,欢迎大家来交流技术。

  • 相关阅读:
    在线免费生成IntelliJ IDEA 15.0注册码
    SQL logic error or missing database
    angularJs 动态添加upload
    正则表达式 用于验证数字组合(数字之间以逗号分隔)
    angularJs select ng-options 绑定int型的时候绑定失效的坑
    BigDecimal类处理高精度计算
    HttpClient
    activeMQ
    基于SpringMvc图片上传
    SpringMvc实现日期转换
  • 原文地址:https://www.cnblogs.com/qicosmos/p/3540435.html
Copyright © 2020-2023  润新知