• <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等類似  回復  更多評論   

            欧美777精品久久久久网| 精品一久久香蕉国产线看播放| 欧美一区二区精品久久| 无码日韩人妻精品久久蜜桃| 久久久久99精品成人片三人毛片| 69国产成人综合久久精品| 亚洲精品国精品久久99热一| 久久久亚洲欧洲日产国码是AV| 欧洲性大片xxxxx久久久| 亚洲国产精品综合久久一线| 久久99热这里只有精品国产| 久久综合给合综合久久| 亚洲午夜精品久久久久久app| 亚洲国产成人精品女人久久久| 久久男人中文字幕资源站| 亚洲午夜无码AV毛片久久| 欧美精品国产综合久久| 亚洲国产精品一区二区久久hs| 久久久av波多野一区二区| 久久99精品国产| 久久精品国产亚洲5555| 久久人人爽人人爽人人片AV东京热 | 精品久久久久久久| 伊人久久综在合线亚洲2019| 国产激情久久久久影院老熟女免费 | 久久er热视频在这里精品| 精品无码久久久久久国产| 一级a性色生活片久久无少妇一级婬片免费放| 无码乱码观看精品久久| 伊人色综合久久天天人手人婷| 精品国际久久久久999波多野| 国产成人精品久久亚洲高清不卡| 久久婷婷五月综合97色直播| 久久久久免费看成人影片| 久久久久一级精品亚洲国产成人综合AV区 | 久久99精品久久久久久动态图| 国产精品免费久久| 婷婷五月深深久久精品| 久久精品无码一区二区日韩AV| 久久久久人妻一区精品性色av| 久久久久亚洲精品无码网址 |