亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

瘦身前后——兼談C++語言進化

2019-11-17 04:59:56
字體:
來源:轉載
供稿:網友
  前一陣子寫了一篇文章,提到語言進化的職責之一,就是去除語言中的tricks(職責之二是去除非本質復雜性)。

  ??次襜log的朋友肯定記得我曾寫過的boost源碼剖析系列。本來這個系列是打算成書的,但隨著對C++的熟悉發生了一些轉變,對語言級技術的熱衷逐漸消退,再回過頭來看boost庫中的一些組件,發現原本覺得很有寫的必要的東西頓時消失了。Scott Meyers的主頁上也列有一個寫Boost Under The Hood的計劃,一直也不見成文,興許也有類似的原因。

  一門語言應該是“Make simple things simple, make complex things possible”的。當我們用語言來表達思想的時候,這門語言應該能夠提供這樣的能力:即讓我們能夠最直接地表達我們的意思,多一分則太多,少一分則太少,好比古人形容
// in C

DIR* dir = opendir(".");

if(NULL != dir)

{

strUCt dirent* de;

for(; NULL != (de = readdir(dir)); )

{

struct stat st;

if( 0 == stat(de->d_name, &st) &&

S_IFREG == (st.st_mode & S_IFMT))

{

remove(de->d_name);

}

}

 closedir(dir);

}

  那能叫KISS?

  總之還是那句話:明確知道你想要表達的是什么并用最簡潔(在不損害輕易理解性的前提下)的方式去表達它。但我認為,最KISS不代表最原始。

  進化——兩個例子

  先舉一個平易近人的例子(Walter Bright——D語言發明者——曾在他的一個
PResentation中使用這個例子),假如我們想要遍歷一個數組,在C里面我們是這么做(或者用指針,不過指針有指針自己的問題):

int arr[10];

… // initialize arr

for(int i = 0; i < 10; ++i)

{

int value = arr[i];



printf

}

  這個貌似簡單的循環其實有幾個主要的問題:

  1. 下標索引不應該是int,而應該是size_t,int未必能足夠存放一個數組的下標。

  2. value的類型依靠于arr內元素的類型,違反DRY,假如arr的類型改變為long或unsigned,就可能發生截斷。

  3. 這種for只能對數組工作,假如是另一個自定義容器就不行了。

  在現代C++里面,則是這么做:

for(std::vector<int>::iterator

iter = v.begin();

iter != v.end();

++iter) {



}

  其實最大的問題就是一天三遍的寫,麻煩。for循環的這個問題上篇講auto的時候也提到。

  Walter Bright然后就把D里面支持的foreach拿出來對比(當然,支持foreach的語言太多了,這也說明了這個結構的高效性)。

foreach(i; v) {



}

  不多不少,剛好表達了意思:對v中的每個元素i做某某事情。

  這個例子有人說太Na?ve了,其實我也贊成,的確,天天不知道有多少程序員寫下一個個的循環結構,究竟有多少出了上面提到的三個問題呢?最大的問題恐怕還是數組越界。此外大家也都親身體驗過違反DRY原則的后果:改了一處地方的類型,編譯,發現到處都是類型錯誤,結果一通“查找——替換”是免不了的了,誰說程序員的時間是寶貴的來著?

  既然這個例子太Nave,那就說一個不那么Nave的。java為什么要加入closure?以C++STL為例,假如我們要:

transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), _1 + _2);

  也就是說將v1和v2里面的元素對應相加然后放到v3當中去。這里用了boost.lambda,但大家都知道boost.lambda又是一個經典的雞肋。_1 + _2還算湊活,一旦表達式復雜了,或者其中牽涉到對其它函數的調用了,簡直就是一場噩夢,比如說我們想把v1和v2中相應元素這樣相加:f(_1) + f(_2),其中f是一個函數或仿函數,可以做加權或者其它處理,那么我們可以像下面這樣寫嗎:

transform(…, f(_1) + f(_2));

  答案是不行,你得這樣寫:

transform(…,

boost::bind(std::plus<int>(), boost::bind(f, _1), boost::bind(f, _1))

);

  Lisper們笑了,Haskeller們笑了,就連Javaer們都笑了。It’s not even funny! 這顯然違反了“simple things should be simple”原則。

  假如不想卷入C++ functional的噩夢的話,你也可以這么寫:

struct Op

{

int Operator()(int a1, int a2) { return f(a1) + f(a2); }

};

transform(…, Op());

  稍微好一點,但這種做法也有很嚴重的問題。

  為什么Java加入closure,其實還是一個語法問題。從嚴格意義上,Java的anonymous class已經可以實現出一樣的功能了,正如C++的functor一樣。然而,代碼是給人看的,語言是給人用來寫代碼的,代碼的主要代價在維護,維護則需要閱讀、理解。寫代碼的人不希望多花筆墨來寫那些自己本不關心的東西,讀代碼的人也希望“所讀即所表”,不想看到代碼里面有什么彎子,最好是自然語言自然抽象才好呢。

  所以,盡管closure是一顆語法糖,但卻是一顆很甜很甜的糖,因為有了closure你就可以寫:

transform(…, <>(a1, a2){ f(a1) + f(a2) });

Simple things should be simple!

  此外,closure最強大的好處還是在于對局部變量的方便的引用,設想我們想要創建的表達式是:

int weight1 = 0.3, weight2 = 0.6;

transform(…, f(_1)*weight1 + f(_2)*weight2);

  當然,上面的語句是非法的,不過使用closure便可以寫成:

int weight1 = 0.3, weight2 = 0.6;

transform(…, <&>(_1, _2){ f(_1)*weight1 + f(_2)*weight2 } );

  用functor class來實現同樣的功能則要麻煩許多,一旦麻煩,就會error-prone,一旦error-prone,就會消耗人力,而人力,就是金錢。

  C++09也有希望加入lambda,不過這是另一個話題,下回再說。

The Real Deal——variadic templates

  C++的callback類,Google一下,沒有一打也有半打。其中尤數boost.function實現得最為靈活周到。然而,就在其靈活周到的接口下面,卻是讓人不忍卒讀的實現;03年的時候我寫的第一篇boost源碼剖析就是boost.function的,當時還覺得能看懂那樣的代碼牛得不行...話說回來,那篇文章主要剖析了兩個方面,一個是它對不同參數的函數類型是如何處理的,第二個是一個type-erase設施。其中第一個方面就占去了大部分的篇幅。

  簡而言之,要實現一個泛型的callback類,就必須實現以下最常見的應用場景:

function<int(int, int)> caller = f;

int r = caller(1, 2); // call f

  為此function類模板里面肯定要有一個operator(),然而,接下來,如何定義這個operator()就成了問題:

template<Signature>

class function

{

operator()(???);

};

  ???處填什么?返回值處的???可以解決,用一個traits:typename result_type<Signature>::type,但參數列表處的???呢?

  boost采用的辦法也是C++98唯一的辦法,就是為不同參數個數的Signature進行特化:

template<typename R, typename T1>

class function<R(T1)>

{

R operator()(T1 a1);

};

template<typename R, typename T1, typename T2>

class function<R(T1, T2)>

{

R operator()(T1 a1, T2 a2);

};

template<typename R, typename T1, typename T2, typename T3>

class function<R(T1, T2, T3)>

{

R operator()(T1 a1, T2 a2, T3 a3);

};


… // 再寫下去頁寬不夠了,打住…

  如此一共N(N由一個宏控制)個版本。

  這種做法有兩個問題:一,函數的參數個數始終還是受限的,你作出N個特化版本,那么對N+1個參數的函數就沒轍了。boost::tuple也是這個問題。二,代碼重復。每個特化版本里面除了參數個數不同之外基本其它都是相同的;boost解決這個問題的辦法是利用宏,宏本身的一大堆問題就不說了,你只要打開boost.function的主體實現代碼就知道有多糟糕了,近一千行代碼,其中涉及元編程和宏技巧無數,可讀性可以說基本為0。好在這是個標準庫(boost.function將加入tr1)不用你維護,假如是你自己寫了用的庫,恐怕除了你誰也別想動了。所以第二個問題其實就是可讀性可維護性問題,用Matthew Wilson的說法就是可發現性和透明性的問題,這是一個很嚴重的問題,許多C++現代庫因為這個問題而遭到詬病。

  現在,讓我們來看一看加入了variadic templates之后的C++09實現:

template<typename R, typename... Args>

struct invoker_base {

virtual R invoke(Args...) = 0;

virtual ~invoker_base() { }

};

template<typename F, typename R, typename... Args>

struct functor_invoker : public invoker_base<R, Args...>

{

eXPlicit functor_invoker(F f) : f(f) { }

R invoke(Args... args) { return f(args...); }

private:

F f;

};

template<typename Signature>

class function;

template<typename R, typename... Args>

class function<R (Args...)>
{

public:

template<typename F>

function(F f) : invoker(0)

{

invoker = new functor_invoker<F, R, Args...>(f);

}
R operator()(Args... args) const
{

return invoker->invoke(args...);

}
private:

invoker_base<R, Args...>* invoker;

};

  整個核心實現就這些!一共才36行!加上析構函數拷貝構造函數等邊角料一共也就70行!更重要的是,整個代碼清楚無比,所有涉及到可變數目個模板參數的地方都由variadic templates代替?!癆rgs…”恰如其分的表達了我們想要表達的意思——多個參數(數目不管)。與C++98的boost.function實現真是天壤之別!

  這里function_invoker是用的type-erase手法,具體可參見我以前寫的boost.any源碼剖析,或上篇講auto的,或《C++ Template Metaprogramming》(內有元編程慎入?。?。type-erase手法是像C++這樣的弱RTTI支持的語言中少數真正實用的手法,某種程度上設計模式里面的adapter模式也是type-erase的一個變種。

  假如還覺得不夠的話,可以參考variadic-templates的主頁,上面的variadic templates proposal中帶了三個tr1實現,分別是tuple,bind,function,當然,variadic-templates的好處遠遠不僅僅止于這三個實現,從本質上它提供了一種真正直接的表達意圖的工具,完全避開了像下面這種horrible的workaround:

template<class T1>

cons(T1& t1, const null_type&, const null_type&, const null_type&,

const null_type&, const null_type&, const null_type&,

const null_type&, const null_type&, const null_type&)

: head (t1) {}

  tuple的C++98實現,代碼近千行。利用variadic-templates實現,代碼僅百行。

  和這種更horrible的workaround:

template<class R, class F, class A1, class A2, class A3, class A4, class A5, class A6>

_bi::bind_t<R, F, typename _bi::list_av_6<A1, A2, A3, A4, A5, A6>::type>

BOOST_BIND(boost::type<R>, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)

{

typedef typename _bi::list_av_6<A1, A2, A3, A4, A5, A6>::type list_type;

return _bi::bind_t<R, F, list_type>(f, list_type(a1, a2, a3, a4, a5, a6));

}

  小小的boost.bind,實現代碼逾兩千行,其間重復代碼無數。用了variadic-templates,實現不過百行。

  BTW. variadic templates在C++大會上一次性幾乎全數投票通過。lambda能不能進標準則要看幾個提案者的工作。目前還沒有Wording出來。不過只要出了wording想必也會像variadic templates那樣壓倒性通過的。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品国产一区二区三区久久| 欧美尤物巨大精品爽| 午夜精品久久久久久久久久久久| 中文国产成人精品久久一| 国产偷亚洲偷欧美偷精品| 久久影院资源网| 精品一区二区电影| 精品电影在线观看| 色婷婷av一区二区三区久久| 91日韩在线视频| 欧美中文在线免费| 91精品久久久久| 一本色道久久88综合日韩精品| 欧美日韩精品在线播放| 午夜欧美不卡精品aaaaa| 成人欧美在线视频| 国产欧美一区二区三区四区| 亚洲欧洲激情在线| 国内精品久久久久久久久| 成人性生交大片免费观看嘿嘿视频| 亚洲一区二区三区香蕉| 91国自产精品中文字幕亚洲| 日本精品久久电影| 全球成人中文在线| 国产精品久久久久久久久男| 欧美激情第一页xxx| 欧美日韩国产中文精品字幕自在自线| 日韩欧美在线免费| 日韩精品视频中文在线观看| 亚洲欧美在线播放| 日韩a**站在线观看| 91精品视频免费观看| 狠狠躁18三区二区一区| 亚洲a成v人在线观看| 性金发美女69hd大尺寸| 成人激情电影一区二区| 国模视频一区二区三区| 日韩欧美a级成人黄色| 中文字幕亚洲一区二区三区五十路| 亚洲精品av在线| 国产999在线观看| 亚洲aa在线观看| 欧美亚洲国产日本| 欧美天天综合色影久久精品| 中文字幕日韩av综合精品| 亚洲精品456在线播放狼人| 午夜精品一区二区三区在线视| 亚洲精品999| 欧美精品在线播放| 成人在线国产精品| 久久久久日韩精品久久久男男| 国产99久久精品一区二区 夜夜躁日日躁| 色www亚洲国产张柏芝| 久久中文精品视频| 国产精品亚洲一区二区三区| 黑人巨大精品欧美一区二区免费| 精品视频偷偷看在线观看| 午夜精品在线观看| 成人乱人伦精品视频在线观看| 久久99久国产精品黄毛片入口| 国产精品精品一区二区三区午夜版| 国产精品视频久| 美日韩丰满少妇在线观看| 欧美成人免费在线视频| 欧美日本高清一区| 欧美大尺度在线观看| 日韩av在线网站| 日韩中文字幕在线观看| 国产精品高清免费在线观看| 国产精品久久久久久久天堂| 久热精品在线视频| 亚洲欧美综合图区| 久久精品视频在线| 久久久久久噜噜噜久久久精品| 亚洲美女视频网| 欧美激情一区二区三区成人| 国产a∨精品一区二区三区不卡| 亚洲天堂男人天堂女人天堂| 成人午夜小视频| 国产亚洲视频在线| 欧美亚洲国产成人精品| 91精品久久久久久久久青青| 怡红院精品视频| 亚洲国内精品在线| 久久99国产精品久久久久久久久| 日韩电影免费观看在线| 日韩国产激情在线| 欧美丝袜美女中出在线| 97色在线观看免费视频| 日韩国产在线播放| 日韩h在线观看| 日韩在线观看网站| 亚洲日本欧美日韩高观看| 久久久国产视频91| 国产一区二区三区久久精品| 欧美另类在线播放| 中文字幕欧美精品在线| 国产精品第一第二| 欧美老肥婆性猛交视频| 91精品国产高清| 97在线视频免费观看| 亚洲精品999| 最近2019年好看中文字幕视频| 国产视频精品va久久久久久| 91精品久久久久久久久久另类| 97在线视频精品| 久久91精品国产91久久久| 日本成人黄色片| 91亚洲人电影| 一区二区欧美激情| 亚洲国产私拍精品国模在线观看| 亚洲精品国产精品国产自| 久久久久久久久久久久久久久久久久av| 国产成人小视频在线观看| 成人动漫网站在线观看| 韩剧1988在线观看免费完整版| 最近中文字幕2019免费| 亚洲欧美中文日韩在线v日本| 亚洲tv在线观看| 日韩av三级在线观看| 亚洲美腿欧美激情另类| 国自产精品手机在线观看视频| 国产成人久久精品| 欧美放荡办公室videos4k| 精品中文视频在线| 国产精品主播视频| 欧美在线一级视频| 欧美xxxx综合视频| 国产成人aa精品一区在线播放| 日韩免费在线视频| 亚洲欧美另类在线观看| 亚洲免费视频一区二区| 国产视频久久久久| 91国产精品电影| 最近2019年手机中文字幕| 亚洲开心激情网| 日韩精品视频在线观看网址| 欧美激情亚洲一区| 久久久久久欧美| 亚洲va国产va天堂va久久| 亚洲成年人在线| 国产成人极品视频| 亚洲色在线视频| 日韩国产精品视频| 久久av中文字幕| 欧美国产精品人人做人人爱| 精品久久久久久久久久国产| 亚洲人成电影在线| 色无极影院亚洲| 日韩欧美国产一区二区| 久久精品国产精品| 91精品视频免费观看| 国产综合福利在线| 欧美色播在线播放| 亚洲人成在线免费观看| 欧美性猛交xxxx免费看久久久| 91精品国产综合久久香蕉922| 国产精品久久久久久久久影视| 在线播放精品一区二区三区| 欧美一区二区三区免费观看| 欧美成人午夜激情在线| 久久91亚洲精品中文字幕奶水| 国产精品黄页免费高清在线观看| 97国产在线观看|