C++ Primer 第五版 第十六章 練習題編程題目答案

https://github.com/jzplp/Cpp-Primer-Answer

error C2678: 二進制“<”: 沒有找到接受“const Sales_data”類型的左操作數的運算符(或沒有可 接受的轉換)
note: 可能是“內置 C++ operator<(double, double)”
note: 嘗試匹配參數列表“(const Sales_data, const Sales_data)”時
note: 參見對正在編譯的函數 模板 實例化“int compare<Sales_data>(const T &,const T &)”的 引用
        with
        [
            T=Sales_data
        ]
error C2678: 二進制“<”: 沒有找到接受“const Sales_data”類型的左操作數的運算符(或沒有可 接受的轉換)
note: 可能是“內置 C++ operator<(double, double)”
note: 嘗試匹配參數列表“(const Sales_data, const Sales_data)”時
  • 練習16.4
    16.4 程序代碼

  • 練習16.5
    16.5 程序代碼

  • 練習16.6
    16.6 程序代碼

  • 練習16.7
    16.7 程序代碼

  • 練習16.8
    因爲!=僅需要判斷對象是否相等,而<需要判斷對象的大小關係,相等關係相對更容易定義,適用範圍更廣

  • 練習16.9
    函數模板是用來生成針對不同類型的函數的模板。 類模板是用來生成針對不同類型的類的模板。

  • 練習16.10
    類模板被實例化時生成針對特定類型的類。

  • 練習16.11
    修改:

template<typename elemType> class ListItem;
template<typename elemType>
class List
{
public:
    List();
    List(const List &);
    List & operator=(const List &);
    ~List();
    void insert(ListItem<elemType> *ptr, elemType value);
private:
    ListItem<elemType> * front, * end;
};
  • 練習16.12
    Blob類 書上的版本
    實現了書上未定義的各種成員 也實現了ConstBlobPtr類模板
    16.12 Blob.h程序代碼
    16.12 測試程序代碼

  • 練習16.13
    選擇了建立對應類型示例的友好關係,因爲同類型的類和相關成員是在操作上相關的,不同類型模板實例的是在操作上無關的。

  • 練習16.14
    Screen類和Window_mgr類 書上的版本
    用類模板進行了重寫並添加了重載的輸入輸出運算符
    16.14 Screen.h程序代碼
    16.14 測試程序代碼

  • 練習16.15
    已經在練習16.14中添加

  • 練習16.16
    Vec類
    由書上的StrVec類用類模板進行了重寫
    16.16 Vec.h程序代碼
    16.16 測試程序代碼

  • 練習16.17
    關鍵字class和typename在模板類型參數中含義相同,只不過typename出現時間較晚

  • 練習16.18

(a) 非法。修改:
template <typename T, typename U, typename V> void f1(T, U, V);
(b) 合法  
(c) 合法  
(d) 非法。修改:
template <typename T> void f4(T, T);
(e) 合法 
extren template class vector<string>;
聲明模板類vector的string實例,定義在別處
template class vector<Sales_data>;
定義模板類vector的Sales_data實例
  1. const引用和指針的轉換
  2. 數組或函數指針的轉換
  • 練習16.34
    (a) 不合法,因爲是引用類型,數組長度不同
    (b) 合法,T爲 char [4]

  • 練習16.35
    (a) 合法 T爲char
    (b) 合法 T爲double
    (c) 合法 T爲char
    (d) 不合法 參數類型不同

  • 練習16.36

(a) T爲int * 
(b) T1爲int *,T2爲int * 
(c) T爲const int * 
(d) T1爲const int *,T2爲const int * 
(e) T爲const int * 
(f) T1爲int *,T2爲const int * 
  • 練習16.37
    不能直接傳給他一個int和double,可以顯示指定模板實參進行調用

  • 練習16.38
    因爲make_shared是可以構造一個參數類型的對象的,因此我們需要指定模板參數類型,否則編譯器無法從函數實參來推斷模板實參的

  • 練習16.39

compare<std::string>("11qwe", "12345")
  • 練習16.40
    合法,It的實參類型的解引用必須是一個可以加0的對象。返回類型是It的實參類型的解引用對象的常量引用

  • 練習16.41

template <typename T1, typename T2>
auto sum(T1 a, T2 b) -> decltype(a + b)
{
    return a + b;
}
  • 練習16.42
(a) T : int &  val : int &
(b) T : const int & val : const int &
(c) T : int val : int &&
  • 練習16.43
T : int & val : int &
  • 練習16.44
template<typename T> void g(T val);
(a) T : int val : int 
(b) T : int val : int
(c) T : int val : int
template<typename T> void g(const T & val);
(a) T : int val : const int &
(b) T : int val : const int &
(c) T : int val : const int &
  • 練習16.45
    如果用一個42調用g,則42是字面值常量,是右值,因此T爲int,val爲int && 類型。
    如果用一個int類型變量調用g,因爲變量是左值,將一個左值傳遞給函數的右值引用參數,編譯器會推斷模板T的類型爲int & ,這樣val的類型就是 int & &&,摺疊後就是 int &

  • 練習16.46
    這段代碼是要把元素從舊地址移動到新地址,雖然是左值,但是我們確定移動是安全的。
    首先elem是string * 類型,*elem++是令elem指向下一個位置,同時返回當前位置對象的左值引用。 然後用std::move函數令左值類型轉換爲右值引用,再傳參給alloc.construct函數,令其利用這個右值移動到新的內存中。

  • 練習16.47
    16.47 程序代碼

  • 練習16.48
    debug_rep模板重載函數 書上的版本
    16.48 程序代碼

  • 練習16.49

g(42)
候選函數:
void g<int>(int);
最後選擇:
void g<int>(int);
g(p)
候選函數:
void g<int *>(int *);
void g<int>(int *);
最後選擇:
void g<int>(int *);
g(ci)
候選函數:
void g<int>(int);
最後選擇:
void g<int>(int);
g(p2)
候選函數:
void g<const int *>(const int *);
void g<const int>(const int *);
最後選擇:
void g<const int>(const int *);
f(42)
候選函數:
void f<int>(int);
最後選擇:
void f<int>(int);
f(p)
候選函數:
void f<int *>(int *);
void f<int>(const int *);
最後選擇:
void f<int *>(int *);
f(ci)
候選函數:
void f<int>(int);
最後選擇:
void f<int>(int);
f(p2)
候選函數:
void f<const int *>(const int *);
void f<int>(const int *);
最後選擇:
void f<int>(const int *);
void g(T t)
void g(T * t)
void g(T t)
void g(T * t)
void f(T t)
void f(T t)
void f(T t)
void f(const T * t)

結果相同

  • 練習16.51
    猜測結果爲:
foo(i, s, 42, d);
sizeof...(Args) 爲 3
sizeof...(rest) 爲 3
foo(i, 42, "hi");
sizeof...(Args) 爲 2
sizeof...(rest) 爲 2
foo(d, s);
sizeof...(Args) 爲 1
sizeof...(rest) 爲 1
foo("hi");
sizeof...(Args) 爲 0
sizeof...(rest) 爲 0
  • 練習16.52
    16.52 程序代碼

  • 練習16.53
    重載的可變參數函數模板的print函數 書上的版本
    16.53 程序代碼

  • 練習16.54
    會發生編譯錯誤

  • 練習16.55
    調用大於1個的除ostream實參時會發生編譯錯誤。
    因爲print可變參數函數遞歸到只剩一個除ostream實參時,傳遞給下一個遞歸的rest中沒有任何元素,不能匹配T,因此出現編譯錯誤

  • 練習16.56
    可變參數函數模板的errorMsg函數 書上的版本
    16.56 程序代碼

  • 練習16.57
    與舊版本相比,新版本可以接受不同的類型的參數,舊版本只能接受相同類型的,而且還必須放在大括號中
    但是新版本需要遞歸,函數調用次數多,耗費資源多

  • 練習16.58
    StrVec類 書上的版本
    增加了emplace_back函數
    16.58 StrVec.h 程序代碼
    16.58 StrVec.cpp 程序代碼
    16.58 測試程序代碼
    Vec類
    增加了emplace_back函數
    16.58 Vec.h程序代碼
    16.58 測試程序代碼

  • 練習16.59
    由於s是一個string左值,因此Args中的內容爲一個類型,類型爲string &,與&& 摺疊後爲string &
    由chk_n_alloc()確定空間足夠後,std::forward生成一個左值類型,然後傳遞給alloc.construct構造一個string對象

  • 練習16.60
    猜想make_shared的實現方式:
    make_shared是一個可變參數模板的函數,它的第一個模板類型是需要手動指定的,表示了構造的類型。
    後面的是可變參數模板。函數形參是可變參數模板類型。
    函數內容是new一個對象,用std::forward保持參數類型,然後用指針來構造一個shared_ptr,並返回。

  • 練習16.61
    shared_ptr2類
    模仿標準庫的shared_ptr,自己實現
    增加了make_shared2函數
    16.61 shared_ptr2.h程序代碼
    16.61 DebugDelete.h程序代碼
    16.61 測試程序代碼

  • 練習16.62
    Sales_data類 書上的版本
    增加了特例化的hash<Sales_data>
    測試代碼僅本題使用
    16.62 Sales_data.h程序代碼
    16.62 Sales_data.cpp程序代碼
    16.62 測試程序代碼

  • 練習16.63
    函數模板,統計給定值在vector中出現的次數
    16.63 程序代碼

  • 練習16.64
    函數模板,統計給定值在vector中出現的次數
    增加了處理const char * 的特例化版本
    16.64 程序代碼

  • 練習16.65
    debug_rep模板重載函數
    另char * 和const char * 成爲模板的特例化版本
    16.65 程序代碼

  • 練習16.66
    優點:
    不會影響重載函數的匹配規則
    缺點
    不能實現重載函數的匹配規則優先級的提升
    需要嚴格遵守模板的定義規則

  • 練習16.67
    如果對於之前沒特例化的版本來講,是和之前函數匹配規則不一樣
    但是特例化的版本不會提高優先級,因此不會影響正常函數的匹配規則

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章