• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            loop_in_codes

            低調做技術__歡迎移步我的獨立博客 codemaro.com 微博 kevinlynx

            像寫函數式語言代碼一樣寫C++


            忘記最早接觸函數式編程語言是什么時候了,也忘記接觸的第一門函數式語言是哪一門。斷斷續續接觸過好幾種函數式語言(當然都算不純的,ruby/lisp不算純吧),這些語言的思想在潛移默化中多多少少對我有所影響。

            我是個C++程序員,我不知道我平時寫的都是些什么代碼。最讓人印象深刻就是我會經常寫遍歷STL容器的代碼,是經常,這樣的遍歷你可能也不陌生:

            for (ListType::iterator it = con.begin(); it != con.end(); ++it) {
                something
            }

            或者針對std::map/set等的查找:

            Table::iterator it = table.find(key);
            if (it == table.end())
                
            do-something
            do-something

            多虧STL接口的一致性,這讓我們寫出了很多“一致性“代碼。慢慢地我覺得惡心,不禁想起函數式編程語言中,對于這種需求一般都會提供類似的接口:

            con.map(function (it) if (it->some-filed == some-value) return something end)
            # 或者
            con.each 
            do |it| if it.some-filed == some-value then return something end end
            # 或者
            (con.map (lambda (it) (
            if ((= it.some-filed some-value)) (return something))))

            (好吧,lisp我又忘了)總之,這種針對容器的遍歷操作,都會成為一種內置接口,并且通過lambda來讓用戶直接編寫處理代碼,少去寫循環的冗余。然后,我寫了類似下面的一組宏(隨手敲的不保證能運行):

            #define IT_N __it

            #define TRAVERSE_MAP(type, map, exps) \
                
            for (type::iterator IT_N = map.begin(); IT_N != map.end(); ++IT_N) { \
                    exps; \
                }
            #define I_KEY (IT_N->first)
            #define I_VALUE (IT_N->second)

            #define TRAVERSE_LIST(type, list, exps) \
                
            for (type::iterator IT_N = list.begin(); IT_N != list.end(); ++IT_N) { \
                    exps; \
                }
            #define L_VALUE (*IT_N)

            #define FIND_MAP_ITEM(type, map, key, fexps, texps) \
                
            do { \
                    type::iterator IT_N 
            = map.find(key); \
                    
            if (IT_N == map.end()) { \
                        fexps; \
                    } 
            else { \
                        texps; \
                    } \
                } 
            while(0)

            #define VAL_N __val
            #define FIND_LIST_ITEM_IF(type, list, cmp, fexps, texps) \
                
            do { \
                    
            struct Comp { \
                        
            bool operator() (const type::value_type &VAL_N) const { \
                            
            return cmp; \
                        } \
                    }; \
                    type::iterator IT_N 
            = std::find_if(list.begin(), list.end(), Comp()); \
                    
            if (IT_N != list.end()) { \
                        texps; \
                    } 
            else { \
                        fexps; \
                    } \
                } 
            while(0)

            #define NULL_EXP ;

            當然,以上接口都還包含一些const版本,用于const容器的使用。使用的時候(截取的項目中的使用例子):

            TRAVERSE_MAP(TimerTable, m_timers, 
                    I_VALUE.obj
            ->OnTimerCancel(I_KEY, I_VALUE.arg);
                    TIMER_CANCEL(I_VALUE.id)); 

            TRAVERSE_LIST(AreaList, areas,
                    ids.push_back(L_VALUE
            ->ID()));

            FIND_MAP_ITEM(PropertyTable, m_properties, name,
                    LogWarn(
            "set a non-existed property %s", name.c_str()); return NIL_VALUE,
                    
            if (val.Type() != I_VALUE.type()) {
                        
            return NIL_VALUE; 
                    } 
            else {
                        GValue old 
            = I_VALUE;
                        I_VALUE 
            = val; 
                        
            return old;
                    });

            多虧了C/C++宏對一切內容的可容納性,可以讓我往宏參數里塞進像if這種復合語句,甚至多條語句(例如最后一個例子)。這些宏我使用了一段時間,開始覺得挺爽,很多函數的實現里,我再也不用寫那些重復的代碼了。但是后來我發覺這些代碼越來越惡心了。最大的弊端在于不可調試,我只能將斷點下到更深的代碼層;然后就是看起來特不直觀,連作者自己都看得覺得不直觀了,可想而知那些連函數式編程語言都不知道是什么的C++程序員看到這些代碼會是什么心情(可以想象哥已經被詛咒了多少次)。

            函數式語言讓人寫出更短的代碼,這一點也對我有影響,例如我最近又寫下了一些邪惡代碼:

            // split a string into several sub strings by a split character i.e:
            // "a;b;c;" => "a", "b", "c"
            // "a;b;c" => "a", "b", "c"
            std::vector<std::string> SplitString(const std::string &str, char split) {
                std::vector
            <std::string> ret;
                size_t last 
            = 0;
                
            for (size_t pos = str.find(split); pos != std::string::npos; last = pos + 1, pos = str.find(split, last)) {
                    ret.push_back(str.substr(last, pos 
            - last));
                }
                
            return last < str.length() ? ret.push_back(str.substr(last)) : 0, ret;
            }

            惡心的就是最后那條return語句,因為我需要處理”a;b;c”這種c后面沒加分隔符的情況,但我并不愿意為了這個需求再寫一個會占超過一行的if語句。因為,我太喜歡ruby里的if了:


            do-something if exp

            也就是ruby里允許這種只有一行if的代碼將if放在其后并作為一條語句。我的不愿意其實是有理由的,在c/c++中有太多只有一行條件體的if語句,對這些語句參合進編程風格/可讀性進來后,就不得不讓你寫出不安的代碼,例如:

            if (something) return something; // 某些編程風格里不允許這樣做,因為它不方便調試

            if (something) 
                
            return something; // 某些風格里又有大括號的統一要求

            if (something) {
                
            return something; // 就算符合風格了,但這一條語句就得多個大括號
            }

            if (something) 
            {
                
            return something; // 某些風格里這大括號就更奢侈了
            }

            這個return除了乍看上去有點糾結外,其實也不算什么大問題,但是那個問號表達式返回的0實在沒有任何意義,而正是沒有意義才會讓它誤導人。本來我是可以寫成:

            return last < str.length() && ret.push_back(str.substr(last)), ret;

            這樣利用條件表達式的短路運算,代碼也清晰多了。但是,std::vector::push_back是一個沒有返回值的函數,所以。

            全文完。

            posted on 2012-07-31 09:43 Kevin Lynx 閱讀(3059) 評論(3)  編輯 收藏 引用 所屬分類: c/c++

            評論

            # re: 像寫函數式語言代碼一樣寫C++ 2012-08-01 13:43 fzy

            #define FIDN_MAP_ITEM(type, map, key, fexps, texps) \


            這里FIDN寫錯了
              回復  更多評論   

            # re: 像寫函數式語言代碼一樣寫C++ 2012-08-02 09:31 Kevin Lynx

            @fzy
            thanks,眼神真好!  回復  更多評論   

            # re: 像寫函數式語言代碼一樣寫C++ 2012-08-02 12:26 aa

            不錯 和freebsd中的鏈表/map等類似  回復  更多評論   

            久久人人爽人人爽人人av东京热 | 亚洲人成网亚洲欧洲无码久久| 国产精品无码久久综合网| 人妻少妇久久中文字幕一区二区 | 国产精品久久久久久久app| 国产综合精品久久亚洲| 一本一道久久精品综合| 国产精品久久久亚洲| 久久国产热精品波多野结衣AV| 久久香蕉国产线看观看精品yw| 伊人色综合久久天天人手人婷| 亚洲AV日韩精品久久久久| 香蕉99久久国产综合精品宅男自 | 免费精品99久久国产综合精品| 国产高潮国产高潮久久久| 精品久久人人爽天天玩人人妻| 国产精品中文久久久久久久| 亚洲欧美一区二区三区久久| 久久婷婷是五月综合色狠狠| 亚洲午夜久久久久妓女影院| 久久精品国产99久久久| 国产L精品国产亚洲区久久| 国产精品gz久久久| 亚洲午夜福利精品久久| 国产午夜免费高清久久影院| 久久亚洲国产午夜精品理论片| 久久影视综合亚洲| 亚洲欧美伊人久久综合一区二区| 国产精品久久久久久影院| 狠狠干狠狠久久| 久久久国产打桩机| 99热成人精品免费久久| 精品久久人人爽天天玩人人妻| 国产高潮久久免费观看| 欧美日韩精品久久免费| 久久中文字幕一区二区| 97精品依人久久久大香线蕉97| 亚洲国产成人久久综合碰碰动漫3d | av色综合久久天堂av色综合在| 亚洲国产精品久久久久网站 | 国産精品久久久久久久|