用c++11打造類似於python的range

来源:http://www.cnblogs.com/shouce/archive/2016/02/03/5178919.html
-Advertisement-
Play Games

python中的range函數表示一個連續的有序序列,range使用起來很方便,因為在定義時就隱含了初始化過程,因為只需要給begin()和end()或者僅僅一個end(),就能表示一個連續的序列。還可以指定序列產生的步長,如range(0,10,8)產生的序列為[0, 8], 預設的步長為1,ra


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更強大。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • System類代表系統,系統級的很多屬性和控制方法都放置在該類的內部。該類位於java.lang包。 由於該類的構造方法是private的,所以無法創建該類的對象,也就是無法實例化該類。其內部的成員變數和成員方法都是static的,所以也可以很方便的進行調用。 1、成員變數 System類內部包含i
  • 指定迴圈次數,使用計數器重覆運行語句,語法結構如下: 1 2 3 4 5 For counter = start To end [Step step] [statements] [Exit For] [statements] Next 主要參數: counter:用做迴圈計數器的數值變數。這個變數不
  • scrapy關於日誌文件的記錄
  • JSON字元串的最上一層,肯定是一個JSONObject,JSONObject的下一層,可以包含JSONArray,JSONArray又包含了若幹個JSONObject。用例子來說明: package myJson; import net.sf.json.JSONArray; import net.
  • EXTENDED LIGHTS OUT 題意:給一個5*6的01矩陣,對一個位置操作(0->1開燈或者1->0關燈)會影響到(包括自己)周邊燈狀態反轉。問最後要使得所有的燈關掉的操作矩陣(1表示該位置的燈操作了) 提示:01矩陣,題目給了說是操作兩次就相當於沒操作,但是還有隱含的意思就是這就是一個異
  • 用eclipse創建一個WebService應用非常方便,步驟如下: 1.安裝WebService插件。www.eclipse.org網站上有下載,我下載的是wtp-all-in-one-sdk-R-1.5.4-win32,裡面就包括了。(我下載了好像沒什麼用,估計就跟之前安裝的Eclipse是同一
  • C介面與設計,需要註意的流程還是比較多的. 從演算法設計到演算法測試,到基礎庫封裝, 到基礎庫測試,後面是投入生產, 和框架融合再測試. 等等,都特別的耗時間, 今天分享的 是一個關於二叉樹基庫的封裝測試.下一個版本投入到生產環節.
  • 用單引號代替雙引號來包含字元串,這樣做會更快一些。因為PHP會在雙引號包圍的字元串中搜尋變數,單引號則不會,註意:只有echo能這麼做,它是一種可以把多個字元串當作參數的“函數”(譯註:PHP手冊中說echo是語言結構,不是真正的函數,故把函數加上了雙引號)。 1、如果能將類的方法定義成static
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...