青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-90  評論-947  文章-0  trackbacks-0

如果要 typedef,搞出來的都是些很惡心的名字,自己看了也生氣,還是不搞好了,就 size_t 和 int 玩到底吧。

把 Array 的接口又改得一塌糊涂了,重新貼一下:

namespace xl
{
   
template <typename ValueType>
   
class Array
   
{
   
public:
       
Array(size_t nSize = 0);
       
Array(size_t nSize, const ValueType &tValue);
       
Array(const Array<ValueType> &that);
        ~
Array();

   
public:
       
class Iterator
       
{
       
public:
           
Iterator();
           
Iterator(ValueType *pValue);
           
Iterator(ValueType *pValue, ValueType *pStart, ValueType *pEof);
           
Iterator(const Iterator &that);

       
private:
           
ValueType *m_pStart;
           
ValueType *m_pEof;
           
ValueType *m_pCurrent;

       
public:
           
ValueType &operator * ();
           
ValueType *operator -> ();

       
public:
           
Iterator &operator = (const Iterator &that);
           
bool operator == (const Iterator &that) const;
           
bool operator != (const Iterator &that) const;

       
public:
           
Iterator &operator ++ ();
           
Iterator operator ++ (int);
           
Iterator &operator -- ();
           
Iterator operator -- (int);

       
public:
           
Iterator operator +(int nDistance) const;
           
Iterator operator -(int nDistance) const;
           
Iterator &operator +=(int nDistance);
           
Iterator &operator -=(int nDistance);
        };

       
class ReverseIterator : public Iterator
       
{
       
public:
           
ReverseIterator &operator ++ ();
           
ReverseIterator operator ++ (int);
           
ReverseIterator &operator -- ();
           
ReverseIterator operator -- (int);
        };

   
public:
       
Iterator Begin() const;
       
Iterator End() const;
       
ReverseIterator RBegin() const;
       
ReverseIterator REnd() const;


   
public:
       
Array<ValueType> &operator=(const Array<ValueType> &that);
       
bool operator==(const Array<ValueType> &that) const;
       
bool operator!=(const Array<ValueType> &that) const;

   
public:
       
ValueType &operator[](size_t nIndex);
       
const ValueType &operator[](size_t nIndex) const;

   
public:
       
bool Empty();
       
size_t Size() const;
       
void SetSize(size_t nSize);

   
public:
       
void Insert(const Iterator &itBeforeWhich, const ValueType &tValue);
       
void Insert(const ReverseIterator &itBeforeWhich, const ValueType &tValue);
       
void PushFront(const ValueType &tValue);
       
void PushBack(const ValueType &tValue);
       
template <typename IteratorType>
       
void Insert(const Iterator &itBeforeWhich, const IteratorType &itFirstToInsert, const IteratorType &itAfterLastToInsert);
       
template <typename IteratorType>
       
void Insert(const ReverseIterator &itBeforeWhich, const IteratorType &itFirstToInsert, const IteratorType &itAfterLastToInsert);
       
Iterator Delete(const Iterator &itWhich);
       
ReverseIterator Delete(const ReverseIterator &itWhich);
       
void PopFront();
       
void PopBack();
       
Iterator Delete(const Iterator &itFirstToInsert, const Iterator &itAfterLastToDelete);
       
Iterator Delete(const ReverseIterator &itFirstToInsert, const ReverseIterator &itAfterLastToDelete);
       
void Clear();
       
void SetValue(const Iterator &itWhich, const ValueType &tValue);
       
void SetValue(const ReverseIterator &itWhich, const ValueType &tValue);
       
void SetValue(const Iterator &itFirstToSet, const Iterator &itAfterLastToSet, const ValueType &tValue);
       
void SetValue(const ReverseIterator &itFirstToSet, const ReverseIterator &itAfterLastToSet, const ValueType &tValue);

   
private:
       
ValueType *m_pData;
       
size_t m_nSize;
       
size_t m_nStart;
       
size_t m_nEof;

   
private:
       
void Release();
       
size_t GetWellSize(size_t nSize) const;
       
void MoveData(size_t nIndex, size_t nCount, int nDistance);
       
void CopyData(size_t nIndex, size_t nCount, ValueType *pNewMem) const;

    };
}

主要的考慮,還是想實(shí)現(xiàn)“跨容器的 iterator”(抱歉,我還是覺得這么稱呼挺符合我的預(yù)期的)。只是,在沒有語言層面的 concepts 支持的情況下,如何顯式地讓用戶知道模板參數(shù)要符合哪些條件呢?

在這里再次感謝一下 OwnWaterloo 同學(xué),上篇評論里的東西我會繼續(xù)慢慢琢磨的。^_^

posted on 2009-09-28 23:13 溪流 閱讀(759) 評論(18)  編輯 收藏 引用 所屬分類: C++

評論:
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 00:28 | OwnWaterloo
顯示讓用戶知道么……
有約定俗成
再不成就文檔
再不成…… 只能看源代碼了……

好消息是, 違反concepts一般都錯(cuò)在編譯時(shí),不會將錯(cuò)誤留在運(yùn)行時(shí)……
  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 09:32 | 溪流
@OwnWaterloo

如果有個(gè) template <T> where T is IIterator,用戶看接口定義就知道該怎么做了;可是現(xiàn)在,只能到調(diào)用 Iterator 的某個(gè)具體方法的時(shí)候才報(bào)錯(cuò),用戶理解這個(gè)錯(cuò)誤,就要理解我的實(shí)現(xiàn)了。這不僅增加了學(xué)習(xí)代價(jià),還在一定程度上違背了封裝的初衷,不是么?一點(diǎn)變通的辦法都沒有嗎?
  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 15:55 | 陳梓瀚(vczh)
如果你對效率要求不是跟人家開發(fā)SqlServer的后臺一樣高的話,那就來一個(gè)虛基類吧,當(dāng)成C#的interface用用。虛基類的作用主要在于你可以用他搞類型計(jì)算,譬如說來一個(gè)iterator你就可以知道它的element type是什么,而不用跟stl里面的一樣要求你必須在iterator的里面typedef。而且你還可以做很多iterator<A>到iterator<B>的轉(zhuǎn)換,從map<a,b>到iterator<pair<a,b>>的轉(zhuǎn)換等等。就是慢一點(diǎn)點(diǎn)罷了(真的是一點(diǎn)點(diǎn))。  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 15:56 | 陳梓瀚(vczh)
@OwnWaterloo
壞消息是,那些編譯錯(cuò)誤根本看不懂。  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 15:56 | 陳梓瀚(vczh)
@陳梓瀚(vczh)
我寫了一個(gè)錯(cuò)誤的iterator然后錯(cuò)誤消息竟然是list<T>里面的哪個(gè)代碼用了一個(gè)不存在的函數(shù)  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 16:09 | 陳梓瀚(vczh)
@溪流
template<typename T>
class IEnumerator
{
public:
virtual int Index()const=0;
virtual const T& Current()const=0;
virtual bool MoveNext()const=0;
virtual void Reset()const=0;
virtual bool Available()const=0;
virtual IEnumerator<T>* Clone()const=0;
};

template<typename T>
class IEnumerable
{
public:
virtual IEnumerator<T>* CreateEnumerator()const=0;
};

//注意使用方法
void MyCopy(List<int>& dest, const IEnumerable<int>& source)
{
....
}  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 16:14 | 陳梓瀚(vczh)
@溪流
而且我認(rèn)為作為一個(gè)iterator,我絕對不會想到是Array.SetValue來通過它修改自己的值的  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 18:33 | 溪流
@陳梓瀚(vczh)

virtual IEnumerator<T>* CreateEnumerator()const=0;

這個(gè),到使用的時(shí)候:
IEnumerator<T>* p = CreateEnumerator();
然后求用戶去 delete 嗎?  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 18:33 | 溪流
@陳梓瀚(vczh)

嗯……iterator 一般有哪些約定成俗的規(guī)則?  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 18:35 | 溪流
@陳梓瀚(vczh)

我覺得,出現(xiàn)在具體實(shí)現(xiàn)上的編譯錯(cuò)誤,本不應(yīng)該留給用戶的。最好是在類型檢查的時(shí)候就能報(bào)錯(cuò)。  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 20:23 | OwnWaterloo
OO為什么被人吹捧?
可以說, 是它開創(chuàng)了一個(gè)歷史,人們開始普遍采用 "對抽象的、多態(tài)的事物編程"。
 
在那之前, 無論是OP還是OB, 都只能完成模塊化, 方便分工開發(fā)與測試。很少使用多態(tài)技術(shù)。

OB編程(OP就省了…… OP->OB依然能完成一定復(fù)用,但方式不同):
void f_ob(T v) { v.f(); }
 
f是針對一個(gè)具體的T進(jìn)行編程。
f的行為和T的行為緊緊綁定在一起。
f想要表現(xiàn)出不同行為, 必須要T表現(xiàn)出不同行為。
但無論T如何改變,T和f都只具有一種行為,最后一次改變后具有的行為。
 

OO編程:

void f_oo(I& i) { i.f(); }
 
f現(xiàn)在的行為, 僅僅與i所表現(xiàn)出的契約綁定在一起。
而i可以有各種各樣的滿足契約的方式
這樣的一大好處就是, 對不同的D : I, f可以被復(fù)用
得到這一好處的前提就是, D 滿足 I與f之間的契約。
 

GP編程:
template<typename T>
void f_gp(T v) { v.f(); }
 
同樣提供了多態(tài)行為:以不同的T帶入f, 就能得到不同的行為。
使得f能被復(fù)用。STL中的組件, 大部分是通過這種方式被復(fù)用的。
并且,STL組件之間, 也大部分是通過這種方式復(fù)用的。
 

1.
無論是GP還是OOP都是組合組件的方式。
它們(典型地)通過concepts 和 interface來抽象出組件多態(tài)行為。
對這種抽象事物編程得到的結(jié)果(函數(shù)/類模板,包),可以被復(fù)用(軟件工程一大目標(biāo))。
-------- -------- -------- -------- -------- -------- -------- --------
 

上面提到契約。
無論是OP、OB、OO、GP, 組件間要能協(xié)同工作, 都是需要契約的。
 
OP:
free 可以接受空指針, 而printf 不行。
前者是free對調(diào)用者定下的約束, 后者也是printf對調(diào)用者定下的約束
—— 要使用我就必須這樣做。
 
malloc 失敗返回空指針, 而new 拋異常, 否則返回可用動態(tài)內(nèi)存。
這是它們對調(diào)用者的承諾。
—— 使用我, 你能得到什么。

T* p = new T;
if (!p)  這種代碼只在古董編譯器上才可能有意義。
 
"加上NULL判斷更好" , 也只有"C++方言"的古董學(xué)者才說得出來。
 
new[] 要 delete[] , new 要 delete, 這也是契約。
"因?yàn)閏har是基礎(chǔ)類型,所以可以new[] , delete", 只有不懂軟件契約的白癡學(xué)者才說得出來。
 

OB:
要將CString s 轉(zhuǎn)換為 TCHAR*, 一定要用 s.GetBuffer  而不是 (TCHAR*)&s[0]
CString 的約束。
 
basic_string.c_str() 一定以'\0'結(jié)尾, 而data() 則不是。
basic_string  的承諾。
 

OOP:
我用的OOP庫、框架不多……  舉不出什么例子。
但它的契約和通常OB"非常類似" : 完成什么、需要調(diào)用什么、調(diào)用順序、 參數(shù)合法性。
 

GP:
GP總共有哪些契約形式, 我總結(jié)不出來。
但至少有一條 —— 它不再對T有完全限定, 而只作最小限定
 

還是上面的代碼:
void f_oo(I& i ) { i.f(); }
D d;
f(d); // 要求 D : I

template<typename T>
void f_gp(T v) { v.f(); }
要求  v.f(); 合乎語法 :比如, 它既可以是non-static member function, 也可以是static member function。
并且僅僅要求這一點(diǎn)
 
 
2.
契約是普遍存在的, 不僅僅是GP、 其他范式都有。
它是合作與復(fù)用的前提。
-------- -------- -------- -------- -------- -------- -------- --------
 
 
3.
為什么GP飽受爭議, 而OO沒有?
我覺得, 是因?yàn)閺腛B到OO過度比較自然
 
 
要求一個(gè)I需要怎樣, 一個(gè)I需要使用者怎樣的時(shí)候,
通常也會有類似的需求 —— 要求一個(gè)C怎樣, 一個(gè)C需要使用者怎樣。
注意, 這只是 client 與 I, 以及 client 與 C之間的契約。
在這個(gè)層面上, 不需要學(xué)習(xí)新的思想。
而下面會提到OO引入的新的契約形式。
 

而GP的契約形式, 都是一些全新的形式
其中最主要的形式是: T 是否具有一個(gè)叫f的函數(shù)(操作符也可以理解為一種調(diào)用函數(shù)的方式)。
在C++中, 還有必須有某個(gè)名字的嵌套類型, 通過T::f強(qiáng)制static member function等形式。

OO比較流行、支持OO的語言比較多,是目前主流。
C++,Java,C#的開發(fā)者總共占了多少比例?
 
GP支持的語言其實(shí)也多。
但拋開C++(或者算上C++用戶中理解GP的人)怎么都比不上上面3個(gè)巨頭。
 

批評自己不熟悉的事物是不嚴(yán)謹(jǐn)?shù)摹?br>遇見STL編譯錯(cuò)誤, 要么就去學(xué)習(xí)GP的方式, 要么就拋棄STL。
抱怨STL是種傻逼行為 —— 明明是自己不會用, 要怪只能怪自己。
 
 
-------- -------- -------- -------- -------- -------- -------- --------
4.
如同GP、 OO同樣需要學(xué)習(xí)、 需要文檔、 否則會充滿陷阱
 
上面提到的client 與 I的契約形式通常和 clinet 與 C之間的形式相同。
使得OO的一個(gè)方面可以"溫固"。
 
而client 與 D之間的契約? 這個(gè)層面不"知新"是不行的。
并且這個(gè)層面上的契約常常是出bug的地方 —— 因?yàn)檫@是語法檢查不了的, 必須有程序員自己去滿足語意。
 
舉個(gè)例子 :
看見一個(gè)虛函數(shù),它是否可以被覆蓋? 覆蓋它的實(shí)現(xiàn)是否需要同時(shí)調(diào)用基類實(shí)現(xiàn)?
除非是約定俗成的一些情況, 比如 OnNotify、OnXXXEvent這種名字比較明顯。
其他情況, 不去看文檔, 依然是不知道的。
 
 
我剛剛就犯了一個(gè)錯(cuò)。
python 中 繼承HTMLParser , 覆蓋__init__ 時(shí), 必須調(diào)用基類實(shí)現(xiàn)。
我確實(shí)不知道構(gòu)造函數(shù)也可以被完全覆蓋……(原諒我…… 第1次使用python……)
在C++中, 基類的構(gòu)造函數(shù)是無論如何都會被調(diào)用的。
 
 
我沒有調(diào)用基類的__init__, 然后報(bào)了一個(gè)錯(cuò)。
好在報(bào)錯(cuò)清晰, 源代碼的位置都有, 源代碼也可見, 源代碼也清晰。問題很容易就找出來了。
 
 
如果
4.1.
它不是構(gòu)造函數(shù), 只是一個(gè)普通的虛函數(shù)?
名字也看不出什么蹊蹺?
 
4.2.
文檔也沒有記載是否需要調(diào)用基類?
(HTMLParser中的文檔沒有說要調(diào)用__init__, 這應(yīng)該是python的慣例, 所以就沒有記載了)
沒有嚴(yán)格的錯(cuò)誤檢查?
沒有完整的、信息豐富的call stack trace?
等發(fā)現(xiàn)錯(cuò)誤時(shí), 也許都離題萬里了。
 
4.3.
沒有清晰的源代碼(其實(shí)到了要查看源代碼的時(shí)候, 已經(jīng)是……)?
 

這些問題在OO中同樣是存在的, 只是它沒引起編譯錯(cuò)誤, 或者說編譯錯(cuò)誤比較明顯, 容易修改。
而更多的語意檢查, OO中 client 與 D之間的層次, 依然要靠程序員的學(xué)識 —— 主要是查閱文檔的習(xí)慣。

對比GP
4.1之前的4.0(OnNotify, OnXXXEvent之流), 同樣存在一些約定俗成。
 
對4.1, 同樣是查文檔。
 
對4.2, 沒有文檔同樣犯錯(cuò)。
C++中, 一部分錯(cuò)誤可以提前到編譯時(shí)(C++只在持編譯時(shí)支持ducking type)
 
對4.3
同樣需要去查看源代碼。
 
GP的代碼比OOP難看? 
同上面, 只是因?yàn)?strong>不熟悉、不信任、不需要這種抽象方法, 這些契約的形式。
 

STL中的契約形式其實(shí)并不多。
[first,last) 左閉右開區(qū)間;
iterator的幾個(gè)種類;
(adaptable)binary(unary)_function;boost只是將其提升到N-nary,還省去了adaptable的概念;
相等、等價(jià)、嚴(yán)格弱序。
多嗎?
 
而且, 我不覺得為了比較要去實(shí)現(xiàn)一個(gè)IComparable 有何美感可言……
 
 
-------- -------- -------- -------- -------- -------- -------- --------
5. 這些新的契約形式、 抽象方式, 有沒有其優(yōu)勢
當(dāng)然有 —— 最小依賴帶來的靈活性
上面也提到, GP只依賴于其需要的契約, 對其不需要的, 通通不關(guān)心。
 
 
現(xiàn)在詳細(xì)解釋上面
D d;
f_oop(d); // D : I
 
T v;
f_gp(v);    // v.f
 
為什么后者比前者靈活。因?yàn)楹笳咧灰蕾囁枰臇|西。
 
5.1
template<typename T>
void f123_gp(T v) { v.f1(); v.f2(); v.f3(); }
 
可以使用
struct T123_1 { void f1(); void f2(); void f3(); }
struct T123_2 { void f1(); void f2(); void f3(); }
 

void f123_oop(I& i) { i.f1(); i.f2(); i.f3(); }
必須有一個(gè)
struct I { virtual void f1(); virtual void f2(); virtual void f3(); };
然后是:
D1 : I; D2 : I; ...
 
 
5.2
如果現(xiàn)在需要實(shí)現(xiàn)另一個(gè)函數(shù), 它對T的需求更少 :

template<typename T>
void f12_gp(T v) { v.f1(); v.f2(); }

T123_1, T123_2 可以使用
 
新增一個(gè):
struct T12_1 { void f1(); void f2(); }
依然可以使用
 

OOP就必須重構(gòu)了:

struct I12 { virtual void f1(); virtual void f2(); };
struct I123 : I12 { virtual void f3(); }
struct D12 : I12 {};
 
5.3
再看 :
template<typename T>
void f23_gp(T v) { v.f2(); v.f3(); }

T123_1, T123_2 依然可以使用
T12_1 不行。
 
但新增的
struct T23_1 { void f2(); void f3(); }; 可以使用
 
 
OOP又必須重構(gòu):
總體趨勢是這樣的, OOP需要極端靈活的時(shí)候, 就會變成這樣:
一個(gè)接口, 一個(gè)函數(shù)
struct I1 { virutal void f1(); };
struct I2 { virutal void f2(); };
struct I3 { virutal void f3(); };
現(xiàn)在接口設(shè)計(jì)是極端靈活了。

但使用接口時(shí), 依然逃不過2種都不太優(yōu)雅的作法:
1. 接口組合
struct I12 : I1, I2;
struct I23 : I2, I3;
struct I31 : I3, I1;

2. 接口查詢
不組合出那些中間接口, 但運(yùn)行時(shí)作接口查詢:
void f12(I1* i1) {
  i1->f1();
  if (I2* i2 = dynamic_cast<I2*>(i1) {
     i2->f2();
  }
  else { 將一部分編譯時(shí)錯(cuò)誤留到了運(yùn)行時(shí)。 }
}
這不是故意找茬, 而是將STL中的iterator換個(gè)簡單的形式來說明而已。
 

也許絕大部分情況下, 是不需要靈活到每個(gè)接口一個(gè)函數(shù), 而是一個(gè)接口3、4個(gè)相關(guān)的函數(shù)。通常它們會被一起使用。

即使沒有上面如此極端, 假設(shè)IPerfect1、IPerfect2都是設(shè)計(jì)得十分合理的, 3、4個(gè)函數(shù)的接口, 通常這3、4個(gè)函數(shù)要么必須一起提供, 要么都不提供, 單獨(dú)提供是不符合語意的, 提供太多又是不夠靈活的。
這需要經(jīng)驗(yàn), 相當(dāng)多的經(jīng)驗(yàn)。 但總是可以完成的事情。
 
但組合接口, 依然是OOP的痛處。
我記不清C#和Java中的interface是否繼承自多個(gè)interface
如果不行, 它們就可能需要運(yùn)行時(shí)接口查詢。
而C++, 要在這種"組合接口"與接口查詢之前作一個(gè)選擇。
 
反觀GP, 它一開始就不是以接口為單位來提供抽象,而是按需而定
所以, 它既不需要仔細(xì)的拆分接口, 也不需要組合接口。
STL中數(shù)據(jù)、容器、算法相互無關(guān)、可任意組合。
應(yīng)該是前無古人的突破。
后面有沒有來者? 上面已經(jīng)說了, OOP要達(dá)到這種靈活性, 同樣也有其代價(jià)。
并且, OOP代價(jià)體現(xiàn)在丑陋, 而不是難以理解
 

靈活的事物肯定比不那么靈活的事物難理解,抽象總比具體難理解。
所以抽象出一個(gè)合理的、廣泛接受的語意很重要。

* 就是解引用, ++ 就是前迭代, -- 就是后迭代。
支持--就是雙向, 支持 + n 就是隨機(jī)。
 
GP也不會胡亂發(fā)明一些語意不清晰的概念。
window w;
control c;
w += c; 這種代碼在GP界同樣是收到批評的。
 
 
最后, 軟件工程中, 是否真正需要靈活到如此程度, 以至于大部分人難以(或者不愿意去)理解的事物, 我就不知道了……
  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 22:16 | 溪流
@OwnWaterloo

讀了這么多文字,真是受益良多。

但必須指出的是,上面對于 OOP 和 GP 的某些比較是不公平的。在 OOP 中,只有你需要去繼承它的時(shí)候(即你需要修改這個(gè)類),你才需要了解源代碼,需要了解跟實(shí)現(xiàn)相關(guān)的“契約”。如果僅僅是使用的話,那么,給出全部 public class 的 public method 的聲明,應(yīng)該所有的使用者都不會犯語法錯(cuò)誤,編譯器會提供完備的類型檢查。而同樣是使用(并不是去修改),GP 中,卻需要去了解它的實(shí)現(xiàn),這不是很不公平嗎?我們不是追求為了隱藏不必要的細(xì)節(jié),讓使用者減輕負(fù)擔(dān)嗎?當(dāng)然,如果要去修改它,那么對它的實(shí)現(xiàn)是必須要了解的了。
  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-29 23:07 | OwnWaterloo
@溪流
嗯嗯, 你說得很對。

假設(shè)多態(tài)的使用者與多態(tài)抽象之間的層面叫A, 還有多態(tài)提供者與多態(tài)抽象之間的層面叫B。
OOP中的A和OB很相似, 只有B是新加的內(nèi)容。
而GP中, 無論A、B, 都是新鮮內(nèi)容。

所以這樣比較是不公平的~_~


我至今沒有完全明白rbtree的實(shí)現(xiàn), 但不妨礙我使用map和set。
對一般的內(nèi)建類型, 或者符合STL規(guī)范的值類型, 直接使用即可。
如果需要放自定義類型,需要了解的就是key_compare和嚴(yán)格弱序。
也不算多吧? OOP同樣離不開比較準(zhǔn)則, 只是key_compare換成了ICompare。
如果還想高級一些, 還可以去了解allocator, 那是篇幅更長的一套規(guī)范。
OOP沒見有這功能, 不比較了。

boost中有一些庫, 我知道實(shí)現(xiàn)原理, 但不知道對付各種編譯器的trick。
還有一些隱約知道原理, 更多的是不知道。
boost的源代碼我一份都沒看過(堅(jiān)持不下去…… 確實(shí)很丑陋, 但很多代碼都是為了對付不同編譯器而已)

舉個(gè)例子, any。 即使沒看源代碼, 我也知道這個(gè)庫應(yīng)該在何時(shí)使用, 以及如何使用 —— 因?yàn)槲铱戳宋臋n…… 不多的。 interface也需要看文檔的吧?

但就是這么一個(gè)小東西, 使得我可以通過一個(gè)參數(shù)傳遞任何東西。
并且不再需要繼承自某個(gè)基類……

"一切皆為Object" —— 我覺得這是很可笑的事情。
Finder.find?
p1.fuck(p2); 還是 p2.fuck(p1);? 3p呢?
太可笑了……

而且在java和C#中實(shí)現(xiàn)free function其實(shí)并不難, 只是它們固執(zhí), 不愿意加入而已。

OOP根本就不是一種純粹的編程范式。 不結(jié)合其他范式, OOP根本就寫不出程序來。 不知道那些追求所謂"純OO"的家伙是怎么想的 ……
在我眼里, OO只有oo analysis, oo design, oo programming只是oo design而已。 實(shí)現(xiàn)design時(shí), 是命令式的。
至少對java, c#的OO來說是如此。

不是我一人這么說, 你還可以去看看《冒號課堂》。


上面有點(diǎn)小錯(cuò)誤, 糾正一下:
C/C++中本來就可以以單一參數(shù)傳遞任何東西……
any 是使得這一作法類型安全而已。
當(dāng)然, 既然使用C/C++寫代碼, 不同與那些保姆語言, 程序員自己就要對類型安全負(fù)責(zé)。 所以any通常是為了堵住那些對類型安全尤為重視的人的嘴而已。
我還是更喜歡void* ...

真不知道那些成天叫囂著類型安全, 卻視generic加入java是一種退步, 使得java不純粹的人是怎么想的……
難道"不犯錯(cuò)", 比"犯了錯(cuò)總有人補(bǔ)救" 更重要?  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-30 00:04 | OwnWaterloo
上上面關(guān)于interface和concepts的比較, 是因前不久給一個(gè)項(xiàng)目經(jīng)理解釋ducking type和以函數(shù)為單位的抽象形式, 但沒成功……

現(xiàn)在算是想得比較清楚了, 但好像沒表達(dá)清楚…… 那么多文字, 我自己都不愿意看第2遍……


整理一下:

對單個(gè)"契約"的設(shè)計(jì)而言, 通過interface或是concepts沒有什么區(qū)別。
并且interface比concepts更廣為人知。
所以當(dāng)時(shí)怎么都沒能說服他……

interface的劣勢(也就是concepts的優(yōu)勢)體現(xiàn)在"如何拆解與組合契約"上。
如何拆分,設(shè)計(jì)interface, 是門學(xué)問。
那幾個(gè)方法通常是應(yīng)該整體提供的?
這就是interface的劣勢的本質(zhì) —— 它總是要將若干方法"打包"到一起才可以。
極端情況, 只含有一個(gè)方法的interface也很常見, Dispose所屬接口就是。

interface更麻煩的地方在于組合。
當(dāng)一個(gè)f需要若干種interface的功能時(shí), 要么必須將一些interface繼續(xù)"打包", 形成一個(gè)新的, 要么運(yùn)行時(shí)檢查。


而concepts打從一開始, 就僅僅依賴所需要的東西, 不需要"打包"這一過程。
拆分和組合是自由的。
從某種程度上來說, 這也容易造成晦澀的設(shè)計(jì)。
但什么設(shè)計(jì)不是學(xué)問呢…… interface的設(shè)計(jì)同樣需要經(jīng)驗(yàn)。


concepts相比interface來說, 限制更少, 也更靈活。
這種靈活性是本質(zhì)上的 —— 因?yàn)椴淮嬖?quot;打包"這一限制 ——是不以現(xiàn)實(shí)編程中是否需要這種程度的靈活性,以及這種靈活性是否會被人們普遍接受而轉(zhuǎn)移的。


靈活的事物通常難以掌握, 如果現(xiàn)實(shí)編程中不需要, 人們不理解、不接受, 也只能算是當(dāng)前條件下的劣勢 —— 對太多數(shù)人來說晦澀、復(fù)雜, 無法被廣泛使用。
如果哪天人們接受了呢?



還有一點(diǎn), 上面說的GP和OO、OOP概念太廣泛。 OO、OOP的定義到底是什么, 各有各的說法。
所以改為 concepts 和 interface( in java and C# )的比較, 比較準(zhǔn)確。
并且某些其他支持OO的語言 —— 現(xiàn)在是個(gè)語言都要說自己支持OO, 不支持的也要改為支持... ——中, 是不需要interface這種"契約打包器"的。



樓主啊, 我自我感覺比較好的建議, 就只有建議你實(shí)現(xiàn)一套侵入式容器(包括樹式堆)而已, 既鍛煉了技巧, 又不陷入"重復(fù)發(fā)明輪子"。

其他的, 都是自說自話 …… 不必想太多-_-

因?yàn)樽錾线@行了,沒什么時(shí)間總結(jié)平時(shí)的一些零散想法。
如果是中學(xué)做習(xí)題, 會因?yàn)樽鲋鲋?就累了 …… 就轉(zhuǎn)而"總結(jié)一下吧,比單純做來得有效, 同時(shí)休息休息"。
而寫代碼…… 是沒有累的感覺的…… 就會一直寫下去……
只有在討論的時(shí)候, 才會想去總結(jié)一些東西。
把你的blog評論區(qū)當(dāng)吐槽了…… sorry ...
  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-09-30 00:49 | 溪流
@OwnWaterloo

非常歡迎吐槽~哈哈
關(guān)于侵入式和非侵入式,說實(shí)話我也是前幾天第一次聽你說。我稍微查了下,不是很確切的了解其含義。前面我在 Iterator 里放了個(gè) Array *m_pArray,后來拿掉了,改成放一個(gè) ValueType *,有沒有改變侵入式/非侵入式方面的屬性呢?  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-10-01 14:16 | OwnWaterloo
@溪流
我out了……

boost 已經(jīng)有 intrusive 容器的實(shí)現(xiàn)了……
http://www.boost.org/doc/libs/1_35_0/doc/html/intrusive/intrusive_vs_nontrusive.html

我這里的boost版本非常老…… 1.33…… 所以沒發(fā)現(xiàn)……  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-10-12 18:39 | 陳梓瀚(vczh)
@OwnWaterloo
當(dāng)然interface比起純GP還有一個(gè)好處,就是你可以對一個(gè)具體的類,譬如IEnumerable<int>得到類型推導(dǎo)結(jié)果int,但是你沒法對一個(gè)隨便什么object只是長得跟IEnumerator<int>一樣的東西來得到類型推導(dǎo)結(jié)果int。這(類型推導(dǎo))是GP更大的價(jià)值,可以跟OOP一起,OOP充當(dāng)抽象,GP用來做推導(dǎo),能做出很多漂亮的用法來。譬如說:

MyList<int> list;(繼承自IEnumerator<int>)
list>>Where(某個(gè)函數(shù))的結(jié)果一定是IEnumerator<int>,編譯器推導(dǎo)了。

反而vector<int>也想要支持的話,你會發(fā)現(xiàn)所有的容器都要寫一遍……所以我只需要讓我的容器都支持IEnumerator<T>,然后GP對IEnumerator<T>進(jìn)行類型推導(dǎo)即可,提供10個(gè)功能我只寫10個(gè)函數(shù)。如果是vector<int>+list<int>+queue<int>什么的,提供10個(gè)功能要寫10×n個(gè)函數(shù),n==容器數(shù)量。

當(dāng)然這僅僅是對于【容器】而言的。至于你剛才討論的很多都是其他的東西,就不納入了。  回復(fù)  更多評論
  
# re: 算了,還是不 typedef 了,類型真煩 2009-10-12 19:15 | OwnWaterloo
@陳梓瀚(vczh)
需求是iterator類型推導(dǎo)iterator解引用后的類型?
嘿嘿,真的不能嗎?

#include <iterator>
MyIt it1,it2;
typename std::iterator_traits<MyIt>::value_type // 這就是你要的
v = *it1;

// 除此之外還有其他幾種類型信息。
typename std::iterator_traits<MyIt>::pointer p = &v;
typename std::iterator_traits<MyIt>::reference r = v;
typename std::iterator_traits<MyIt>::difference_type d
= std::distance(it1,it2);

typename std::iterator_traits<MyIt>::iterator_category tag;
tag決定了iterator能做什么。

algorithm中的所有需要iterator的算法,都和容器完全無關(guān)。
和iterator相關(guān)的類型信息都是這么取得的。
自然不存在M*N(M=算法的數(shù)量,N=容器的數(shù)量)的說法。
而是M(M=算法數(shù)量)。


給你舉個(gè)例子可能比較明顯:
需要value_type的算法我一時(shí)還想不出來……
來個(gè)其他的需要difference_type的意思意思:
template<typename InIt,typename T>
typename iterator_traits<InIt>:: difference_type // 返回類型
count(InIt first,InIt last,const T& v) {
typename iterator_traits<InIt>:: difference_type c = 0;
for (;first!=last; ++first) if (*first==v) ++c;
return c;
}



這是GP的類型推導(dǎo)方式 —— 嵌入類型。這用法漂亮嗎?


實(shí)現(xiàn)這一魔法的工作:
iterator_traits只需實(shí)現(xiàn)一次。
各個(gè)容器其實(shí)不需要做什么工作。
工作在每一個(gè)iterator類型上,它必須有這幾種嵌套類型。
當(dāng)然,iterator頭文件中提供了std::iterator, 可以繼承自它而得到這幾種嵌套類型。
不過我一般喜歡自己寫,繼承可能會影響空基類優(yōu)化。
多嗎?


而且,有一點(diǎn)OOP是辦不到的。 所有的iterator都不需要有一個(gè)"基類"。
T arr[size];
&arr[0] 類型是T*, 是iterator,而且還是random_access。但是它的基類應(yīng)該是什么才好呢?
它只有4字節(jié)。OOP就那個(gè)vptr就4字節(jié)了,加點(diǎn)數(shù)據(jù)再加上padding,8字節(jié)至少。



"反而vector<int>也想要支持的話,你會發(fā)現(xiàn)所有的容器都要寫一遍……"
這是什么需求? 需要所有容器都寫一遍? 說出來看看?  回復(fù)  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            9国产精品视频| 久久不射中文字幕| 日韩一二三在线视频播| 欧美日韩国产小视频| 亚洲无线观看| 欧美亚洲视频一区二区| 黄色欧美日韩| 亚洲精品影院| 国产欧美一区二区精品忘忧草| 午夜久久美女| 久久野战av| 亚洲一区二区三区在线观看视频 | 在线观看日韩| 亚洲精品一区二区三区在线观看| 国产精品高潮呻吟久久av黑人| 欧美在线影院在线视频| 美女视频黄 久久| 欧美在线视频全部完| 久久综合给合| 99在线精品免费视频九九视| 一本色道久久精品| 在线观看欧美日本| 亚洲一区免费| 亚洲毛片在线| 久久电影一区| 亚洲午夜精品17c| 鲁鲁狠狠狠7777一区二区| 亚洲尤物精选| 欧美电影打屁股sp| 久久久国产精品一区二区中文| 嫩草国产精品入口| 久久婷婷国产综合国色天香| 欧美精品一区二区三区在线播放| 久久精品久久综合| 欧美日韩高清一区| 欧美高清视频一二三区| 国产目拍亚洲精品99久久精品| 亚洲黄网站黄| 国产在线成人| 亚洲男女毛片无遮挡| 99国产一区二区三精品乱码| 久久狠狠一本精品综合网| 亚洲制服欧美中文字幕中文字幕| 蜜桃av一区二区三区| 老牛影视一区二区三区| 国产精品手机视频| 亚洲视频在线观看网站| 一区二区欧美亚洲| 欧美国产视频一区二区| 欧美大片国产精品| 黑人巨大精品欧美一区二区| 一区二区欧美亚洲| 亚洲无限av看| 欧美视频在线观看视频极品| 亚洲欧洲在线播放| 日韩视频免费大全中文字幕| 久久综合一区| 亚洲第一精品夜夜躁人人爽 | 久久久九九九九| 久久久亚洲国产美女国产盗摄| 国产精品一二三| 亚洲一区在线直播| 欧美在线免费观看视频| 国产精品夜夜夜| 久久国产精品久久久久久| 久久久蜜桃一区二区人| 精品福利免费观看| 欧美成人精品| 亚洲伦理中文字幕| 亚洲欧美日产图| 国产日韩亚洲欧美精品| 久久国内精品自在自线400部| 老巨人导航500精品| 亚洲精品美女久久7777777| 欧美激情网站在线观看| 99国产精品国产精品久久| 亚洲一区三区电影在线观看| 国产精品扒开腿做爽爽爽视频 | 亚洲精品久久久久久下一站 | 日韩视频在线免费观看| 欧美丰满少妇xxxbbb| 91久久久久久久久久久久久| 免费成人高清视频| 一本色道久久| 久久精品主播| 亚洲欧洲精品成人久久奇米网| 欧美久久婷婷综合色| 亚洲综合清纯丝袜自拍| 久久米奇亚洲| 日韩天堂av| 国产欧美日本一区视频| 美女久久网站| 亚洲午夜电影网| 麻豆精品网站| 亚洲一区二区在线免费观看视频 | 国产精品丝袜xxxxxxx| 久久久www免费人成黑人精品| 亚洲激情在线观看| 久久精品视频导航| 亚洲美女黄网| 在线精品国产欧美| 国产精品久久久久久影院8一贰佰| 久久精品国产96久久久香蕉| 99pao成人国产永久免费视频| 久久精品亚洲| 亚洲性视频网站| 亚洲激情视频在线播放| 国产精品永久免费视频| 欧美母乳在线| 美日韩在线观看| 性色一区二区三区| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 亚洲欧美日韩一区二区| 亚洲国产99精品国自产| 久久久久国产一区二区三区四区 | 欧美专区一区二区三区| 99视频精品免费观看| 精品福利电影| 国产午夜精品全部视频在线播放| 欧美日韩另类字幕中文| 鲁大师成人一区二区三区| 欧美一区二区三区视频免费| 亚洲免费观看高清完整版在线观看熊| 麻豆精品视频在线观看视频| 久久国产精品72免费观看| 亚洲一区二区三区在线观看视频| 亚洲精品久久在线| 91久久精品一区二区别| 极品日韩av| 影音先锋亚洲视频| 一区二区三区在线视频观看| 国产欧美一区二区三区在线看蜜臀| 欧美日韩国产亚洲一区| 欧美日韩国产综合网| 欧美成人激情视频免费观看| 六十路精品视频| 麻豆九一精品爱看视频在线观看免费 | 欧美一级久久| 亚洲欧美在线一区| 亚洲欧美日韩视频二区| 亚洲欧美一区二区精品久久久| 一本色道久久综合亚洲精品婷婷| 亚洲精品免费一区二区三区| 美女网站在线免费欧美精品| 亚洲二区在线观看| 亚洲第一区在线观看| 亚洲国产成人精品女人久久久| 狠狠色丁香婷综合久久| 永久域名在线精品| 亚洲国产精品一区二区久| 最新国产成人在线观看 | 欧美日韩一区二区三区在线观看免| 欧美激情综合色综合啪啪| 欧美精品videossex性护士| 欧美日韩国产一区| 国产精品久久久久aaaa| 国产欧美日韩中文字幕在线| 国产亚洲免费的视频看| 伊人久久大香线蕉av超碰演员| 亚洲国产乱码最新视频| 亚洲精品一区中文| 午夜精品视频一区| 久久亚洲一区| 亚洲日本国产| 亚洲欧美日韩天堂一区二区| 久久久久国产一区二区三区四区| 欧美+亚洲+精品+三区| 欧美性理论片在线观看片免费| 国产精品一区一区三区| 亚洲国产精品传媒在线观看| 一区二区欧美日韩| 久久久久国产成人精品亚洲午夜| 欧美成人在线免费观看| 99精品福利视频| 久久精品视频在线播放| 欧美精品在线视频| 国产一区二区三区成人欧美日韩在线观看 | 精品成人一区二区三区| 一本色道久久| 老牛嫩草一区二区三区日本| 99国内精品久久| 久久视频在线视频| 国产精品久久久久9999吃药| 在线不卡中文字幕播放| 亚洲欧美日本精品| 亚洲国产精品传媒在线观看| 亚洲亚洲精品三区日韩精品在线视频| 久久久成人网| 国产精品一区二区在线观看网站| 亚洲精品中文字幕在线| 久久精品在线视频| 亚洲四色影视在线观看| 欧美国产精品劲爆| 在线播放日韩| 久久久人成影片一区二区三区| 99国产精品99久久久久久粉嫩| 久久综合中文| 狠狠综合久久av一区二区小说| 亚洲视频一起| 亚洲人午夜精品免费|