搜索
熱搜: 活動 交友 discuz
查看: 2771|回復: 0
打印 上一主題 下一主題

[教學] ■C++ Primer p410 上

[複製鏈接]
跳轉到指定樓層
1#
發表於 2007-9-4 09:09:29 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
■C++ Primer p410 上
主題:各編譯器對 auto_ptr 的支援
測試結果:VC6[o]  BCB4[o]  G++[x]
實例:

#001 #include <memory>  // for auto_ptr
#002 using namespace std;
#003 int main()
#004 {
#005    auto_ptr<int> pi(new int(1024));  // G++ error: auto_ptr undeclared.
#006 }

讀者來函:我測試發現 vc6 的「語意」是錯的,它指派給另一個,會造成
          兩個 auto_ptr 都指向同一個物件。BCB5 的結果就正確。


■C++ Primer p411
主題:string* 的建構(直接指定以另一個 string*)
測試結果:VC6[x]  BCB4[o]  G++[o]
實例:

#001 #include <string>
#002 using namespace std;
#003 int main()
#004 {
#005   string *pstr_type = new string( "Brontosaurus" );
#006   string *pstr_type2( pstr_type );  // <== VC6 error.
#007   delete pstr_type;
#008   delete pstr_type2;
#009 }


■p.412 中下
主題:auto_ptr 的 reset() 動作
測試結果:VC6[x]  BCB4[o]  G++[x]
實例:

#001 #include <memory>  // for auto_ptr
#002 using namespace std;
#003 int main()
#004 {
#005   auto_ptr<int> p_auto_int;         // <== G++ error. 見前述 p.410 例
#006   p_auto_int.reset(new int(1024));  // <== VC6 and G++ error
#007 }


■C++ Primer p461
主題:lvalue-to-rvalue 轉換,rvalue-to-lvalue 轉換。
討論:lvalue-to-rvalue 屬於完全吻合(exact match)轉換的一種。
      但是 rvalue-to-lvalue 呢?例如以一個 literal constant 或
      temporary object 指派給一個 reference?應該不行,除非是
      指派給一個 const reference。
測試結果:我的經驗是,各編譯器對此一主題寬緊不一,且無定法(至少我歸納不出)
例一:

#001 int main()
#002 {
#003  int &i = 3;             // (1) should be error
#004                          // rvalue assign to non-const reference
#005  const int &i2 = 3;      // (2) should be ok
#006                          // rvalue assign to const reference
#007  int &i3 = int(3);       // (3) should be error
#008                          // rvalue (temp obj) assign to non-const reference
#009  const int &i4 = int(3); // (4) should be ok
#010                          // rvalue (temp obj) assign to const reference
#011 }
#012
#013 // G++ : (1),(3) warning: initialization of non-const reference `int &'
#014 //                        from rvalue `int'
#015 // jjhou 使用 G++ 2.91.57。
#016 // 據 jyhuang 說,G++ 2.92.2 並不允許通過 (1),(3)。
#017 //
#018 // VC6 : (1),(3) error: 'initializing' : cannot convert from 'const int'
#019 //                      to 'int &'. A reference that is not to 'const'
#020 //                      cannot be bound to a non-lvalue
#021 //
#022 // BCB4: (1),(2),(3),(4) warning: Temporary used to initialize 'i'
#023 //                                in function main ()

例二:

#001 void func1(int  i) { };           // pass by value
#002 void func2(int& i) { };           // pass by reference
#003 void func3(int* i) { };           // pass by pointer
#004 void func4(const int& i) { };     // pass by reference
#005
#006 void main()
#007 {
#008 int i;
#009 const int ci = 5;
#010
#011   func1(i);      // lvalue-to-rvalue, always ok.
#012   func1(ci);
#013   func2(i);
#014   func2(ci);     // (15)
#015   func3(&i);
#016   func3(&ci);    // (17)
#017   func4(i);
#018   func4(ci);
#019
#020   func2(int(6)); // (21), rvalue-to-nonconst-reference.
#021   func4(int(6)); // rvalue-to-const-reference, always ok.
#022 }
#023
#024 /*
#025 VC6 :
#026 (15) : error C2664: 'func2' : cannot convert parameter 1 from
#027        'const int' to 'int &'. Conversion loses qualifiers
#028 (17) : error C2664: 'func3' : cannot convert parameter 1 from
#029        'const int *' to 'int *'. Conversion loses qualifiers
#030 (21) : error C2664: 'func2' : cannot convert parameter 1 from
#031        'int' to 'int &'.
#032        A reference that is not to 'const' cannot be bound to a non-lvalue
#033
#034 BCB4 :
#035 Warning (15): Temporary used for parameter 'i' in call to 'func2(int &)'
#036 Error (17): Cannot convert 'const int *' to 'int *'
#037 Error (17): Type mismatch in parameter 'i' in call to 'func3(int*)'
#038 Warning (21): Temporary used for parameter 'i' in call to 'func2(int &)'
#039
#040 G++ :
#041 (15): warning: conversion from `const int' to `int &' discards const
#042 (3) : warning: in passing argument 1 of `func2(int &)'
#043 (17): warning: passing `const int *' as argument 1 of `func3(int *)' discards const
#044 (21): warning: initialization of non-const reference `int &' from rvalue `int'
#045 (3) : warning: in passing argument 1 of `func2(int &)'
#046 */

例三:詳見「C++ Primer 答客問 (19) part-3」


■p.492, p.499, p.500
主題:以 template nontype parameter 做為陣列尺度(dimension)
測試結果:VC6[x]  BCB4[o]  G++[o]
注意:G++ 對於型別的 const-ness 檢驗極嚴格。以下 (1) 必須改為
      const int ia[5] =...; 才能通過 G++。
實例:

#001 template <class Type, int size>
#002 Type min( const Type (&r_array)[size] ) // VC6 error C2057:
#003 { /* ... */ }                           //  expected constant expression
#004
#005 void main()
#006 {
#007   int ia[5]={40,20,49,17,28}; // (1) 注意,G++ 要求需為 const int ia[5]。
#008   min(ia);
#009 }


■C++ Primer p500 中上
主題:利用轉型運算子,將 template function 在模稜兩可(ambiguous)的環境下
      以某特定型別具現化(instantiated)。
測試結果:VC6[x]  BCB4[x]  G++[x]
實例:

#001 template <typename Type, int size>
#002 Type min( Type (&r_array)[size] ) { /*... */ }  // VC6 error C2057
#003
#004 typedef int (&rai)[10];    // rai:"10 個 ints 組成之陣列" 的 reference.
#005 typedef double (&rad)[20]; // rad:"20 個 doubles 組成之陣列" 的 reference
#006
#007 // overloaded functions
#008 void func( int (*)(rai) ) { };    // int(*)(rai) 是函式指標型別,
#009                                   // 該函式的參數型別是 rai。
#010 void func( double (*)(rad) ) { }; // double(*)(rad) 是函式指標型別,
#011                                   // 該函式的參數型別是 rad。
#012
#013 void main()
#014 {
#015    func(static_cast<double(*)(rad)>(&min));  // (1) 此行無法編譯
#016    // BCB4 E2335: Overloaded 'min' ambiguous in this context
#017    // G++: undefined reference to `func(double (*)(double (&)[19]))'
#018 }

解決之道:繞個道,就可以。將上述 (1):

func(static_cast<double(*)(rad)>(&min));

改為以下即可:

double(*fp)(rad) = &min; // instantiate 'min', using specified type.
func(fp);


■C++ Primer p503
主題:如果 template function 的函式參數型別是一個 class template,
      而實際引數是一個 class,此 class 有個 base class,係從「被指定
      做為函式參數」之 class template 身上具現出來,那麼 template 的
      引數推導可以順利進行。
測試結果:VC6[x]  BCB4[x]  G++[x]
實例:

#001 template <class T>
#002 class Array {  };
#003
#004 template <class T>
#005 class ArrayRC : public Array<T>  {  };
#006
#007 template <class T>
#008 T min4(Array<T>& array) { return T(0); }
#009
#010 void main()
#011 {
#012   ArrayRC<int> ia_rc();
#013
#014   // min4() 的函式引數型別是 ArraryRC<int>,其 base class 為 Array<int>,
#015   // 正是 function template min4() 的函式參數型別 Array<T> 的
#016   // 一個具現體(instantiation),所以 min4() 應該可以接受它(書上說可以)
#017   min4(ia_rc);   // error in VC6, BCB4, G++2.51.97
#018 }

註:2003/01/04 讀者來函,指出將 #012 改為 ArrayRC<int> ia_rc; 即可。
經測試,正確。感謝 royal。

■C++ Primer p507
主題:明白指定 function template 的部份引數的型別,另一部份由編譯器推導而得。
測試結果:VC6[x]  BCB4[x]  G++[o]
實例:

#001 template <class T1, class T2, class T3>
#002    T1 sum( T2 v2, T3 v3)
#003    { return T1(v2+v3); }
#004
#005 typedef unsigned int ui_type;
#006
#007 ui_type calc( char ch, ui_type ui )
#008 {
#009    // 以下明白指定 T1 為 ui_type,
#010    // T2 被編譯器推導為 char,T3 被推導為 ui_type。
#011    ui_type (*pf)( char, ui_type ) = &sum< ui_type >;
#012
#013    ui_type loc = (*pf)(ch, ui);
#014    return loc;
#015 }
#016
#017 void main()
#018 {
#019   calc('c', ui_type(1024));
#020 }


■C++ Primer p508
主題:明白指定 function template 引數型別
測試結果:VC6[x]  BCB4[x]  G++[o]
實例:

#001 template <class T1, class T2, class T3>
#002    T1 sum( T2 op1, T3 op2 ) { /* ... */ return T1(10); }
#003
#004 void manipulate( int (*pf)( int,char ) ) { };
#005 void manipulate( double (*pf)( float,float ) ) { };
#006
#007 void main( )
#008 {
#009    manipulate( &sum< double, float, float > );
#010 }


■C++ Primer p511
主題:separate compilation model for function template
測試結果:VC6[x]  BCB4[x]  G++[x]
          VC6  不支援 export template
          BCB4 支援關鍵字 export,但 linking 時找不到
                temlate instantiation 在哪裡(unresolved external...)
          G++  不支援 export template


■C++ Primer p514
主題:funtion template explicit specialization
注意:書中以 max 為自定之 function template 的名稱。然而有些編譯器已內附
      max 函式(有的是屬於 runtime function,有的是屬於 generic algorithms),
      切莫以為沒有含入相應的 header file,就不會喚起編譯器內附的東西,
      因為有的 header files 會再含入其他 header files,那是表面看不出來的。
      所以,自己的碼千萬不要命名為 max/min,才不會混淆自己。
測試結果:VC6, BCB4, G++ 都支援 funtion template explicit specialization。
      然而在 char*, const char*, const char[], text literal 之間,
      相當混淆而令人迷亂。


■C++ Primer p516
主題:funtion template explicit specialization + argument deduction
測試結果:VC6 表現太寬鬆,不嚴謹。
實例:

#001 #include <iostream>
#002 using namespace std;
#003
#004 template <class T1, class T2, class T3>
#005 T1 sum(T2 op1, T3 op2)
#006 {
#007   cout << "generic form" << endl;
#008   return static_cast<T1>(op1+op2);
#009 }
#010
#011 template<> double sum(float, float);
#012 //上一行在 VC6 竟然可以通過,差勁。
#013 //上一行在 bcb4 出現 e2423: explicit specialization or instantiation
#014 //                          of non-existing template 'sum'
#015 //上一行在 G++ 出現 : template-id `sum<>' for `sum<>(float, float)'
#016 //                    does not match any template decaration
#017
#018 // T1 明白指定為 double, T2 推導為 float, T3 推導為 float
#019 template<> double sum<double>(float op1, float op2)
#020 {
#021   cout << "specialization form1" << endl;
#022   return static_cast<double>(op1+op2);
#023 }
#024
#025 // T1, T2, T3 明白指定為 int, char, char
#026 template<> int sum<int, char, char>(char op1, char op2)
#027 {
#028   cout << "specialization form2" << endl;
#029   return static_cast<int>(op1+op2);
#030 }
#031
#032 void main()
#033 {
#034 int i=5;
#035 char c='a';
#036 float f=4.5;
#037 double d=6.5;
#038
#039   cout << sum<int>(i, i) << endl;       // generic form  10
#040   cout << sum<double>(f, f) << endl;    // specialization form1  9
#041   cout << sum<int>(c, c) << endl;       // specialization form2  194
#042 }
您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

本論壇為非營利之網路平台,所有文章內容均為網友自行發表,不代表論壇立場!若涉及侵權、違法等情事,請告知版主處理。


Page Rank Check

廣告刊登  |   交換連結  |   贊助我們  |   服務條款  |   免責聲明  |   客服中心  |   中央分站

手機版|中央論壇

GMT+8, 2024-5-2 08:48 , Processed in 0.016893 second(s), 16 queries .

Powered by Discuz!

© 2005-2015 Copyrights. Set by YIDAS

快速回復 返回頂部 返回列表