• <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>

            longshanks

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              14 Posts :: 0 Stories :: 214 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(10)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜


            GP技術的展望——道生一,一生二

            by  莫華楓



                長期以來,我們始終把GP(泛型編程)作為一種輔助技術,用于簡化代碼結構、提高開發效率。從某種程度上來講,這種觀念是對的。因為迄今為止,GP技術還只是一種編譯期技術。只能在編譯期發揮作用,一旦軟件完成編譯,成為可執行代碼,便失去了利用GP的機會。對于現在的多數應用而言,運行時的多態能力顯得尤為重要。而現有的GP無法在這個層面發揮作用,以至于我這個“GP迷”也不得不灰溜溜地聲稱“用OOP構建系統,用GP優化代碼”。

                然而,不久前,在TopLanguage group上的一次討論,促使我們注意到runtime GP這個概念。從中,我們看到了希望——使GP runtime化的希望——使得GP有望在運行時發揮其巨大的威力,進一步為軟件的設計與開發帶來更高的效率和更靈活的結構。
                在這個新的系列文章中,我試圖運用runtime GP實現一些簡單,但典型的案例,來檢測runtime GP的能力和限制,同時也可以進一步探討和展示這種技術的特性。

            運行時多態

                現在的應用側重于交互式的運作形式,要求軟件在用戶輸入下作出響應。為了在這種情況下,軟件的整體結構的優化,大量使用組件技術,使得軟件成為“可組裝” 的系統。而接口-實現分離的結構形式很好地實現了這個目標。多態在此中起到了關鍵性的作用。其中,以OOP為代表的“動多態”(也稱為 “subtyping多態”),構建起在運行時可調控的可組裝系統。GP作為“靜多態”,運用泛化的類型體系,大大簡化這種系統的構建,消除重復勞動。另外還有一種鮮為人知的多態形式,被《C++ Template》的作者David Vandevoorde和Nicolai M. Josuttis稱為runtime unbound多態。而原來的“動多態”,即OOP多態,被細化為runtime bound多態;“靜多態”,也就是模板,則被稱為static unbound多態。
                不過這種稱謂容易引起誤解,主要就是unbound這個詞上。在這里unbound和bound是指在編寫代碼時,一個symbol是否同一個具體的類型 bound。從這點來看,由于GP代碼在編寫之時,面向的是泛型,不是具體的類型,那么GP是unbound的。因為現有的GP是編譯期的技術,所以是 static的。OOP的動多態則必須針對一個具體的類型編寫代碼,所以是bound的。但因為動多態可以在運行時確定真正的類型,所以是runtime 的。至于runtime unbound,以往只出現在動態語言中,比如SmallTalk、Python、Ruby,一種形象地稱謂是“duck-typing”多態。關于多態的更完整的分類和介紹可以看這里
                通過動態語言機制實現的runtime unbound,存在的性能和類型安全問題。但當我們將GP中的concept技術推廣到runtime時會發現,rungime unbound可以擁有同OOP動多態相當的效率和類型安全性,但卻具有更大的靈活性和更豐富的特性。關于這方面,我已經寫過一篇文章 ,大致描述了一種實現runtime concept的途徑(本文的附錄里,我也給出了這種runtime concept實現的改進)。

            Runtime Concept

                Runtime concept的實現并不會很復雜,基本上可以沿用OOP中的“虛表”技術,并且可以更加簡單。真正復雜的部分是如何在語言層面表達出這種runtime GP,而不對已有的static GP和其他語言特性造成干擾。在這里,我首先建立一個基本的方案,然后通過一些案例對其進行檢驗,在發現問題后再做調整。
                考慮到runtime concept本身也是concept,那么沿用static concept的定義形式是不會有問題的:
                  concept myconcept<T> {
                      T& copy(T& lhs, T const& rhs);
                      void T::fun();
                      ...
                  }
                具體的concept定義和使用規則,可以參考C++0x的concept提案這篇文章 ,以及這篇文章
                另一方面,我們可以通過concept_map將符合一個concept的類型綁定到該concept之上:
                  concept_map myconcept<MyType> {}
                相關內容也可參考上述文件。
                有了concept之后,我們便可以用它們約束一個模板:
                  template<myconcept T>void myfun(T const& val); //函數模板
                  template<myconcept T>class X  //類模板
                  {
                       ...
                  };
                到此為止,runtime concept同static concept還是同一個事物。它們真正的分離在于使用。對于static concept應用,我們使用一個具體的類型在實例化(特化)一個模板:
                  X<MyType> x1;  //實例化一個類模板
                  MyType obj1;
                  myfun(obj1);  //編譯器推導obj1對象的類型實例化函數模板
                  myfun<MyType>(obj1);  //函數模板的顯式實例化
                現在,我們將允許一種非常規的做法,以使runtime concept成為可能:允許使用concept實例化一個模板,或定義一個對象
                  X<myconcept> x2;
                  myconcept* obj2=new myconcept<MyType>;
                  myfun(obj2);  //此處,編譯器將會生成runtime版本的myfun
                這里的含義非常明確:對于x2,接受任何符合myconcept的類型的對象。obj2是一個“動態對象”(這里將runtime concept引入的那種不知道真實類型,但符合某個concept的對象稱為“動態對象”。而類型明確已知的對象成為“靜態對象”),符合myconcept要求。至于實際的類型,隨便,只要符合myconcept就行。
                這種情形非常類似于傳統動多態的interface。但是,它們有著根本的差異。interface是一個具體的類型,并且要求類型通過繼承這種形式實現這個接口。而concept則不是一種類型,而是一種“泛型”——具備某種特征的類型的抽象(或集合),不需要在類型創建時立刻與接口綁定。與 concept的綁定(concept_map)可以發生在任何時候。于是,runtime concept實際上成為了一種非侵入的接口。相比interface這種侵入型的接口,更加靈活便捷。
                通過這樣一種做法,我們便可以獲得一種能夠在運行時工作的GP系統。
                在此基礎上,為了便于后續案例展開,進一步引入一些有用的特性:
            1. 一個concept的assosiate type被視為一個concept。一個concept的指針/引用(concept_id*/concept_id&,含義是指向一個符合concept_id的動態對象,其實際類型未知),都被視作concept。一個類模板用concept實例化后,邏輯上也是一個concept。
            2. 動態對象的創建。如果需要在棧上創建動態對象,那么可以使用語法:concept_id<type_id> obj_id; 這里concept_id是concept名,type_id是具體的類型名,obj_id是對象名稱。這樣,便在棧上創建了一個符合concept_id的動態對象,其實際類型是type_id
              如果需要在堆上創建動態對象,那么可以用語法:concept_id* obj_id=new concept_id<type_id>; 這實際上可以看作“concept指針/引用”。
            3. concept推導(編譯期)。對于表達式concept_id obj_id=Exp,其中Exp是一個表達式,如果表達式Exp的類型是具體的類型,那么obj_id代表了一個靜態對象,其類型為Exp的類型。如果表達式Exp的類型是concept,那么obj_id是一個動態對象,其類型為Exp所代表的concept。
              那么如何確定Exp是具體類型還是concept?可以使用這么一個規則:如果Exp中涉及的對象,比如函數的實參、表達式的操作數等等,只要有一個是動態對象(類型是concept),那么Exp的類型就是concept;反之,如果所有涉及的對象都是靜態對象(類型為具體的類型),那么Exp的類型為相應的具體類型。同樣的規則適用于concept*或concept&。
            4. concept轉換。類似在類的繼承結構上執行轉換。refined concept可以隱式地轉換成base concept,反過來必須顯式地進行,并且通過concept_cast操作符執行。兄弟concept之間也必須通過concept_cast轉換。
            5. 基于concept的重載,也可以在runtime時執行,實現泛化的dynamic-dispatch操作。

                下面,就開始第一個案例。

            案例:升級的坦克

                假設我們做一個游戲,主題是開坦克打仗。按游戲的慣例,消滅敵人可以得到積分,積分到一定數量,便可以升級。為了簡便起見,我們只考慮對主炮升級。第一級的主炮是90mm的;第二級的主炮升級到120mm。主炮分兩種,一種只能發射穿甲彈,另一種只能發射高爆彈。因此,坦克也分為兩種:能打穿甲彈的和能打高爆彈的。
                為了使代碼容易開發和維護,我們考慮采用模塊化的方式:開發一個坦克的框架,然后通過更換不同的主炮,實現不同種類的坦克和升級:
                  //一些基本的concept定義
                  //炮彈頭concept
                  concept Warheads<typename T> {
                      double explode(TargetType tt); //炮彈爆炸,返回殺傷率。不同彈頭,對不同類型目標殺傷率不一樣。
                  }
                  //炮彈concept,我們關心的當然是彈頭,所以用Warheads定義一個associate type
                  concept Rounds<typename T> {
                      Warheads WH;
                      ...
                  }
                  //主炮concept
                  concept Cannons<typename T> {
                      Rounds R;
                      void T::load(R& r); //裝填炮彈,load之后炮彈會存放在炮膛里,不能再load,除非把炮彈打出去
                      R::WH T::fire();   //開炮,返回彈頭。發射后炮膛變空,可以再load
                  }
                  //類型和模板定義
                  //坦克類模板
                  template<Cannons C>
                  class Tank
                  {
                      ...
                  public:
                      void load(typenam C::R& r) {
                          m_cannon.load(r);
                      }
                      typename C::R::WH fire() {
                          return m_cannon.fire();
                      }
                  private:
                      C m_cannon;
                  };
                  //主炮類模板
                  template<Rounds Rd>
                  class Cannon
                  {
                  public:
                      typedef Rd R;
                      void load(R& r) {...}
                      typename R::WH fire() {...}
                  }
                  template<Rounds Rd> concept_map Cannons<Cannon<Rd>>{}
                  //炮彈類模板
                  template<Warheads W>
                  class Round
                  {
                  public:
                      typedef W WH;
                      static const int caliber=W::caliber;
                      W shoot() {...}
                      ...
                  };
                  template<Warhead W> concept_map<Round<W>>{}
                  //彈頭類模板,通過traits把各類彈頭的不同行為彈頭的代碼框架分離,使類型“可組裝”
                  concept WH_Traits<T> {
                      return T::exploed(int, TargetType, double, Material);
                  }
                  template<WH_Traits wht, int c>
                  class Warhead
                  {
                  public:
                      const static int caliber=c;
                      double explode(TargetType tt) {
                          return wht::exploed(c, tt, ...);
                      }
                      ...
                  };
                  template<WH_Traits WHT, int c> concept_map<Warhead<WHT, c>>{}
                  //彈頭traits
                  struct KE_WHTraits
                  {
                      static double exploed(int caliber, TargetType tt, double weight, Material m) {...}
                  };
                  concept_map<KE_WHTraits>{}
                  struct HE_WHTraits
                  {
                      static double exploed(int caliber, TargetType tt, double weight, Material m) {...}
                  };
                  concept_map<HE_WHTraits>{}
                  //定義各類彈頭
                  typedef Warhead<KE_WHTraits, 90> WH_KE_90;
                  typedef Warhead<KE_WHTraits, 120> WH_KE_120;
                  typedef Warhead<HE_WHTraits, 90> WH_HE_90;
                  typedef Warhead<HE_WHTraits, 120> WH_HE_120;
                  //定義各類炮彈
                  typedef Round<WH_KE_90> Round_KE_90;
                  typedef Round<WH_KE_120> Round_KE_120;
                  typedef Round<WH_HE_90> Round_HE_90;
                  typedef Round<WH_HE_120> Round_HE_120;
                  //定義各類主炮
                  typedef Cannon<Round_KE_90> Cannon_KE_90;
                  typedef Cannon<Round_KE_120> Cannon_KE_120;
                  typedef Cannon<Round_HE_90> Cannon_HE_90;
                  typedef Cannon<Round_HE_120> Cannon_HE_120;
                  //定義各類坦克
                  typedef Tank<Cannon_KE_90> Tank_KE_90;
                  typedef Tank<Cannon_KE_120> Tank_KE_120;
                  typedef Tank<Cannon_HE_90> Tank_HE_90;
                  typedef Tank<Cannon_HE_120> Tank_HE_120;
                于是,當我們開始游戲時,就可以按照玩家的級別創建坦克對象,并且射擊:
                  //第一級玩家,駕駛發射90mm高爆炮彈的坦克
                  Tank_HE_90 myTank;
                  Round_HE_90 r1;
                  myTank.load(r1);
                  myTank.fire();
                  //第二級玩家,駕駛發射120mm穿甲彈的坦克
                  Tank_KE_120 yourTank;
                  Round_KE_120 r2;
                  yourTank.load(r2);
                  yourTank.fire();
                  //如果這樣,危險,炮彈不匹配,小心炸膛
                  myTank.load(r2); //error
                到目前為止,這些代碼僅僅展示了靜態的GP。concept在這里也只是起到了類型參數約束的作用。但是,在這些代碼中,我們可以明顯地看到,在運用GP 的參數化類型特性之后,可以很容易地進行組件化。對于一組具備類似行為和結構特征的類型,我們可以通過模板的類型參數,將差異部分抽取出來,獨立成所謂的 “traits”或者“policy”。并且通過traits或policy的組合構成不同的產品。在某些復雜的情況下,traits和policy還可以進一步通過traits或policy實現組件化。
                接下來,很自然地應當展開runtime GP的運用了。
                一個游戲者是可以升級的,為了使得這種升級變得更加靈活,我們會很自然地使用Composite模式。現在,我們可以在Runtime concept的支援下實現GP版的Composite模式:
                  //坦克的concept
                  concept tanks<T> {
                      typename Round;
                      void T::load(Round&);
                      Round::WH T::fire();
                  }
                  concept_map tanks<Tank_KE_90>{}
                  concept_map tanks<Tank_HE_90>{}
                  concept_map tanks<Tank_KE_120>{}
                  concept_map tanks<Tank_HE_120>{}
                  //坦克構造函數模板
                  template<tanks T>
                  T* CreateTank(WHType type, int level) { //WHType是一個枚舉表明炮彈種類
                      switch(level)
                      {
                      case 1:
                          if(type==wht_KE)
                              return new tanks<Tank_KE_90>;
                          else
                              return new tanks<Tank_HE_90>;
                      case 2:
                          if(type==wht_KE)
                              return new tanks<Tank_KE_120>;
                          else
                              return new tanks<Tank_HE_120>;
                      default:
                          throw error("no such tank.");
                      }
                  }
                  //玩家類
                  class player
                  {
                  public:
                      void update() {
            m_pTank=CreateTank(m_tankType, ++m_level);
                      }
                      ...
                  private:
                      int m_level;
                      WHType m_tankType;
            tanks* m_pTank;
                  };
                在類player中,使用了一個concept,而不是一個類型,來定義一個對象。根據前面提到的concept推導規則,m_pTank指向一個動態對象,還是靜態對象,取決于為它賦值的表達式類型是concept還是具體類型。在update()函數中,可以看到,m_pTank通過表達式CreateTank(m_tankType, ++m_level)賦值。那么這個函數的返回類型,將決定m_pTank的類型。CreateTank()是一個模板,返回類型是模板參數,并且是符合concept tanks的類型。關鍵在于代碼中的return new tanks<...>語句。前文已經說過,這種形式是使用<...>中的類型創建一個符合tanks的動態對象。所以,CreateTank()返回的是動態對象。那么,m_pTank也將指向一個動態對象。在運行時,當玩家達到一定條件,便可以升級。update()成員函數將根據玩家的級別重新創建相應的坦克對象,賦值到m_pTank中。
                這里,實際上是利用tanks這個concept描述,充當類型的公有接口。它所具有的特性同動多態的抽象基類是非常相似的。但是所不同的是,如同我在代碼中展現的那樣,concept作為接口,可以在任何時候定義,同類型綁定。而無需象抽象基類那樣,必須在類型定義之前定義。于是,這種非侵入式的接口相比抽象基類擁有更加靈活自由的特性。
                然而,事情還沒有完。在進一步深化坦克案例后,我們還將發現runtime GP擁有更加有趣和重要的特性。
                坦克開炮為的是攻擊目標。對目標的毀傷情況直接關系到玩家的生存和得分。所以,我們必須對射擊后,目標的損毀情況進行計算。于是編寫了這樣一組函數:
                  double LethalityEvaluate(Target& t, double hitRate, WH_KE_90& wh) {...}
                  double LethalityEvaluate(Target& t, double hitRate, WH_HE_90& wh) {...}
                  double LethalityEvaluate(Target& t, double hitRate, WH_KE_120& wh) {...}
                  double LethalityEvaluate(Target& t, double hitRate, WH_HE_120& wh) {...}
                Target是目標;hitRate是命中率,根據坦克和目標的位置、射擊參數綜合計算獲得(如果想要更真實,可以加上風向、風力、氣溫、濕度、海拔等等因素);wh就是發射出來的炮彈了。函數返回殺傷率。如此,我們便可以在射擊之后進行評估了:
                  double l=LethalityEvaluate(house, hr, myTank.fire());
                 現在,游戲需要進行一些擴展,增加一個升級,允許坦克升級到第三級。到了第三極,主炮的口徑就升到頭了,但可以升級功能,可以發射穿甲彈和高爆彈。這樣,我們就需要一個“兩用”的主炮類。但是,實際上并不需要直接做這么一個類,只需要用“兩用”的彈藥來實例化Cannon模板:
                  concept Warheads120<T> : Warheads<T> { //120mm炮彈頭concept
                      double LethalityEvaluate(Target& t, double hitRate, T& wh);
                  }
                  concept Rounds120<T> : Rounds<T> {}
                  concept_map Warheads120<WH_KE_120> {}  //120mm的穿甲彈屬于Warheads120
                  concept_map Warheads120<WH_HE_120> {}  //120mm的高爆彈屬于Warheads120
                  template<WH120 WH> concept_map Rounds120<Round<WH>> {} //所有彈頭是Warheads120的炮彈都是屬于Rounds120
                  typedef Canon<Rounds120> Cannon120; //用Rounds120實例化Cannon模板,得到“兩用”主炮
                一堆炫目的concept和concept_map之后,得到Rounds120,就是所謂的“兩用”彈藥。作為一個concept,它同兩種類型map 在一起,實際上就成了這兩個類型的接口。當我們使用Rounds120實例化Cannon<>模板時,也就創建了一個“兩用的主炮”(使用 Rounds120彈藥的主炮)。如果用這個Cannon120實例化Tank模板,那么就可以得到第三級坦克(裝上Cannon120主炮的坦克就是第三級):
                  typedef Tank<Cannon120> TankL3;
                于是,我們可以使用不同的120mm彈藥裝填主炮,并且發射相應的炮彈:
                  TankL3 tank_l3;
                  Round_KE_120 ke_round;  //創建一枚穿甲彈
                  Round_HE_120 he_round;  //創建一枚高爆彈
                  tank_l3.load(ke_round);  //裝填穿甲彈
                  tank_l3.fire();               //發射穿甲彈
                  tank_l3.load(he_round);  //裝填高爆彈
                  tank_l3.fire();               //發射高爆彈
                現在,我們把注意力從消滅敵人,轉移到TankL3::load()的參數類型和TankL3::fire()的返回類型上。在一級和二級坦克(類型 Tank_KE_90等)上,load()成員的參數類型是Round_KE_90等具體的類型;而fire()的返回類型亦是如此。但TankL3是用 Cannon120實例化的,而Cannon120是用Rounds120這個concept實例化的。根據Tank<>模板的定義, load()成員的參數類型實際上是模板參數上的一個associate type。而這個associate type實際上就是Rounds120。這意味著load()實例化后的簽名是:void load(Rounds120& r)(這里暫且允許concept作為類型參數使用)。只要符合Rounds120的類型都可以作為實參傳遞給load()成員。同樣,fire()成員的返回類型來自于Round120上的associate type,也是個concept。因此,fire()實例化后的簽名是:Warheads120 fire()。
                接下來值得注意的是fire()成員。它返回類型是一個concept,那么返回的將是一個動態對象。在運行時,它可能返回WH_KE_120的實例,也可能返回WH_HE_120的實例,取決于運行時load()函數所裝填的炮彈類型。當我們采用LethalityEvaluate()函數對該炮彈的殺傷情況進行評估將會出現比較微妙的情況:
                  double x=LethalityEvaluate(hisTank, hr, tank_l3.fire());
                這時候,編譯器應當選擇哪個LethalityEvaluate()?由于tank_l3.fire()返回的是一個動態對象,具體的類型編譯時不知道。實際上,在正宗的靜態語言中,這樣的調用根本無法通過編譯。當然,編譯器可以通過runtime reflect獲得類型信息,然后在LethalityEvaluate()的重載中匹配正確的函數。然而,這種動態語言做法會造成性能上的問題,為靜態語言所不屑。
                但是,在這里,在runtime concept的作用下,我們可以使這種調用成為靜態的、合法的,并且是高效的。請注意我在concept Warhead120的定義中加入了一個associate function:double LethalityEvaluate(Target& t, double hitRate, T& wh);。runtime concept會很忠實地將concept定義中的associate function構造到一個函數指針表(我稱之為ctable)中。(詳細情況請看本文附錄和這篇文章的附錄)。因此,與tank_l3.fire()返回的動態對象實際類型對應的LethalityEvaluate()函數版本的指針正老老實實地躺在相應的ctable里。所以,我們可以直接從動態對象上獲得指向ctable的指針,并且找出相應的LethalityEvaluate()函數指針,然后直接調用即可。比如:
                  tank_l3.load(ke_round);
                  double x=LethalityEvaluate(hisTank, hr, tank_l3.fire());
                在這些代碼的背后,ke_round通過load()裝填入主炮后,便搖身變成了一個動態對象。編譯器會為它附加上指向ctable的指針,然后在調用 fire()的時候返回指向這個動態對象的引用。此時,編譯器發現這個動態對象所對應的Warhead120 concept上已經定義了一個名為LethalityEvaluate()的associate function,并且簽名與當前調用相符。于是,便可以直接找到ctable中LethalityEvaluate()對應的那個函數指針,無所顧忌的調用。由于一個concept的associate function肯定是同實際類型匹配的函數版本。比如,對于WH_HE_120而言,它的associate function LethalityEvaluate()是版本:double LethalityEvaluate(Target& t, double hitRate, WH_HE_120& wh) {...}。其他版本的LethalityEvaluate()都無法滿足concept Warhead120施加在類型WH_HE_120上的約束。
                這個特性就使得runtime concept作為接口,相比動多態的抽象接口,具有更大的靈活性。抽象接口只表達了類的成員,以及類本身的行為,無法表達類型同其他類型的互動關系,或者說類型間的交互。而concept同時描述了成員函數和相關的自由函數(包括操作符),使得類型間的關系也可以通過接口直接獲得,無需再通過 reflect等間接的動態手段。
                這一點在處理內置類型(如int、float)、預置類型(某些庫中的類型)、第三方類型等不易或無法修改的類型有至關重要的作用。在OOP下,我們無法輸出一個“整數”,或許是short、或許是long,甚至是unsinged longlong。為此,我們要么把它們轉換成一個“最基礎類型”(C/C++的void*,或C#的Object*),然后運用rtti信息進行類型轉換,再做處理;要么使用variant這種類型包裝(就像COM中的那樣),然后為他們全面定義一套計算庫。但runtime concept不僅僅允許輸出“整數”這樣一個動態對象,而且還將相關的各種操作附在動態對象之上,使之無需借助rtti或者輔助類型也可進行各類處理,就如同處理具體類型的對象那樣。
                但是,在這里我僅僅考察了針對一個類型的concept(暫且稱之為一元concept),還未涉及兩個和兩個以上類型的concept(暫且稱為多元 concept,或n-元concept)。在實際開發中,多數操作都會涉及多個對象,比如兩個數相加、一種類型轉換成另一種。此時,我們將會面對多元的 concept。但是多元的runtime concept的特性還不清楚,還需要進一步研究分析。

            總結

                本文初步展示了在引入runtime concept之后,GP的動態化特性。歸納起來有以下幾點:
            1. static GP和runtime GP之間在形式上完全統一,兩者可以看作同一種抽象機制的不同表現。因此,我們在構造類型、函數等代碼實體的時候,并不需要考慮它們將來需要作為static使用,還是runtime使用。static和runtime的控制完全取決于這些代碼實體的使用方式。這就很好地減少了軟件項目早期設計,以及庫設計的前瞻性方面壓力。
            2. runtime concept作為非侵入式的接口,可以非常靈活地使用。我們無需在代碼編寫的一開始就精確地定義好接口,可以先直接編寫功能類型,逐步構建軟件結構。需要時再定義接口(concept),并可以在任何時候與類型綁定。接口的定制可以成為一個逐步推進的過程,早期的接口設計不足產生的不良影響相應地弱化了。
            3. runtime concept相比動多態的抽象接口更加自由。concept可以對類型的成員函數、自由函數、類型特征等等方面的特性作出描述。在runtime化之后,相關自由函數成為了接口的一部分。更進一步規約了類型在整體軟件的代碼環境中的行為特征。同時,也為動態對象的訪問提供更多的信息和手段。
            4. concept不僅實現類型描述,還可以進一步描述類型之間的關系。這大大完善了抽象體系。特別在runtime情況下,這種更寬泛的類型描述能力可以起到兩個作用:其一,進一步約束了動態對象的行為;其二,為外界操作和使用類型提供更多的信息,消除或減少了類型匹配方面的抽象懲罰。這個方面的更多特性尚不清楚,還需要更進一步地深入研究。
                綜上所述,我們可以看到runtime GP在不損失性能的情況下,具備相比動多態更靈活、更豐富的手段。從根本上而言,以concept為核心的GP提供了更基礎的抽象體系(關于這方面探討,請看我的這篇文章中關于concept對類型劃分的作用部分)。或者說,concept的類型描述和約束作用體現了類型抽象的本質,而在此基礎上進一步衍生出static和runtime兩種具體的使用方式。這也就是所謂:道生一,一生二。:)

            附錄

            Runtime Concept實現方案二

                我在這篇文章附錄里,給出了一種實現runtime concept的可能方案。這里,我進一步對這個方案做了一些改進,使其更加精簡、高效。
                假設我們有一個concept:
                concept Shape<T>
                {
                    void T::load(xml);
                    void T::draw(device);
                    void move(T&);
                }
                另外,還有一個代表圓的concept:
                concept Cycles<T> :
                    CopyConstructable<T>,
                    Assignable<T>,
                    Swappable<T>,
                    Shape<T>
                {
                    T::T(double, double, double);
                    double T::getX();
                    double T::getY();
                    double T::getR();
                    void T::setX(double);
                    void T::setY(double);
                    void T::setR(double);
                }
                現在有類型Cycle:
                class Cycle
                {
                public:
                    Cycle(double x, double y, double r);
                    Cycle(Cycle const& c);
                    Cycle& operator=(Cycle const& c);
                    void swap(Cycle const& c);
                    void load(xml init);
                    void draw(device dev);
                    double getX();
                    double getY();
                    double getR();
                    void setX(double x);
                    void setY(double y);
                    void setR(double r);
                private:
                    ...
                };
                我們將類型Cycle map到concept Cycles上:
                  concept_map Cycles<Cycle>{}
                當我們創建對象時,將會得到如下圖的結構:

            runtime concept-2

                concept表(concept list)不再同對象放在一起,而是同一個類型的類型信息放在一起。一同放置的還有ctable。ctable中每個對應的concept項都有一個指向 concept表的指針(也可以指向類型信息頭),用以找到concept list,執行concept cast。動態對象,或動態對象的引用/指針上只需附加一個指向相應的concept的指針即可。相比前一個方案,內存利用率更高。

            posted on 2008-01-06 17:17 longshanks 閱讀(3058) 評論(7)  編輯 收藏 引用

            Feedback

            # re: GP技術的展望&mdash;&mdash;道生一,一生二 2008-01-07 16:00 caoke
            瘋了  回復  更多評論
              

            # re: GP技術的展望&mdash;&mdash;道生一,一生二[未登錄] 2008-01-11 11:25 duguguiyu
            搬個凳子慢慢看。。。  回復  更多評論
              

            # re: GP技術的展望&mdash;&mdash;道生一,一生二 2008-01-14 15:52 duguguiyu
            在贊一次。。。
            我正在做一個二次開發平臺。為了增加擴展性和簡單性,決定不用大而全的接口,而采用動態的模板機制。今看此文,受益匪淺。
            等我有了成熟一些的想法,再找老大討教。。。

            PS:建議莫老大把鏈接的樣式改改,我等看客著實痛苦。。。:)  回復  更多評論
              

            # re: GP技術的展望&mdash;&mdash;道生一,一生二 2008-01-14 20:17 duguguiyu
            Another question...
            如果沒有concept支持有辦法嗎? && 老大用的是什么編譯器,什么concept的實現?。。。

            謝謝。。。  回復  更多評論
              

            # re: GP技術的展望&mdash;&mdash;道生一,一生二 2008-01-15 08:23 longshanks
            to duguguiyu:
            如果沒有concept當然可以,但是必須有一種完成concept功能,也就是類型特征描述的機制,實現模板(泛型)的類型參數約束,以及提供優化線索的功能。
            關于編譯器,靜態concept是未來C++09標準的一部分預計明年可以出臺。據我所知,現在只有一個試驗性編譯器支持concept:conceptGCC,http://www.generic-programming.org/software/ConceptGCC/
            而runtime concept,八字還沒一撇。Bjarne有一篇論文,可能在今年三月份發表,提到了runtime concept。但沒有涉及語言層面的實現,而是庫方面的實現。相關這些內容的其他文獻,可以看我前一篇文章《OOP的黃昏》后面給出的參考。  回復  更多評論
              

            # re: GP技術的展望&mdash;&mdash;道生一,一生二 2008-01-15 08:25 longshanks
            btw:如何才能把鏈接的樣式改成標準樣式?我寫的時候都是藍色帶下劃線的,但是發出來就不見了。  回復  更多評論
              

            # re: GP技術的展望&mdash;&mdash;道生一,一生二 2009-01-21 15:46 kaperx
            比較關心runtime concept的二進制實現,最后那張圖讓我茅塞頓開。
            但是有一個問題,假如在二進制模塊B中引入了新的Concept例如Printable,然后把來自模塊A的class Cycle map到Printable上,那么Printable<Cycle>的concept表如何處理?  回復  更多評論
              

            狠狠色婷婷久久一区二区| 久久久艹| 99久久人妻无码精品系列蜜桃| 99久久精品国产麻豆| 精品一久久香蕉国产线看播放| 日韩久久久久中文字幕人妻| 国产69精品久久久久9999APGF | 伊人久久精品无码av一区| 中文字幕久久精品无码| 国产精品日韩深夜福利久久| 77777亚洲午夜久久多喷| 久久久久女教师免费一区| 中文无码久久精品| 久久国产香蕉视频| 国产99精品久久| 污污内射久久一区二区欧美日韩| 亚洲av日韩精品久久久久久a | 亚洲人成无码www久久久| 久久亚洲AV成人出白浆无码国产| 久久男人中文字幕资源站| 国产91色综合久久免费| 久久久久亚洲AV无码专区体验| 四虎亚洲国产成人久久精品| 91精品国产综合久久精品| 久久夜色精品国产噜噜麻豆 | 91精品久久久久久无码| 国产精品久久久亚洲| 久久亚洲精品无码AV红樱桃| 99精品国产99久久久久久97| 久久精品国产99国产精品亚洲| 久久这里有精品视频| 久久精品国产99久久丝袜| 久久久久国色AV免费看图片| 国产香蕉97碰碰久久人人| 99久久久久| 久久中文精品无码中文字幕| 久久国产精品二国产精品| 国内精品久久久久久久亚洲| 精品久久人人做人人爽综合| 久久丝袜精品中文字幕| 伊人久久大香线蕉精品不卡 |