https://github.com/jzplp/Cpp-Primer-Answer
-
練習16.1
編譯器使用實際的模板實參代替對應的模板參數來創建出模板的一個實例。 -
練習16.2
16.2 程序代碼 -
練習16.3
Sales_data類 書上的版本
測試錯誤信息 僅本題使用
16.3 Sales_data.h程序代碼
16.3 Sales_data.cpp程序代碼
16.3 測試程序代碼
錯誤信息爲:
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) 合法
-
練習16.19
16.19 程序代碼 -
練習16.20
16.20 程序代碼 -
練習16.21
DebugDelete類 書上的版本
16.21 DebugDelete.h程序代碼
16.21 測試程序代碼 -
練習16.22
TextQuery類 書上的版本
Query和繼承類 書上的版本
DebugDelete類 書上的版本
爲TextQuery中的shared_ptr替換刪除器爲DebugDelete 僅本題使用
16.22 DebugDelete.h程序代碼
16.22 TextQuery.h程序代碼
16.22 TextQuery.cpp程序代碼
16.22 Query.h程序代碼
16.22 Query.cpp程序代碼
16.22 測試程序代碼 -
練習16.23
在所有查詢結束,程序結束時會執行調用運算符 -
練習16.24
Blob類 書上的版本
實現了兩個迭代器的構造函數
16.24 Blob.h程序代碼
16.24 測試程序代碼 -
練習16.25
extren template class vector<string>;
聲明模板類vector的string實例,定義在別處
template class vector<Sales_data>;
定義模板類vector的Sales_data實例
-
練習16.26
不可以。因爲vector有調用元素默認構造函數的成員,無法對這個成員實例化,所以無法對vector實例化 -
練習16.27
(a) 未實例化,因爲只是函數聲明
(b) 未實例化,因爲是引用
(c) 實例化了Stack
(d) 未實例化,因爲是指針
(e) 實例化了Stack
(f) 實例化了Stack -
練習16.28
shared_ptr2類
模仿標準庫的shared_ptr,自己實現
make_shared還不會實現
16.28 shared_ptr2.h程序代碼
16.28 DebugDelete.h程序代碼
16.28 測試程序代碼
unique_ptr2類
模仿標準庫的unique_ptr,自己實現
16.28 unique_ptr2.h程序代碼
16.28 DebugDelete.h程序代碼
16.28 測試程序代碼 -
練習16.29
Blob類 書上的版本 僅本題使用
用自己的shared_ptr2類替代shared_ptr
16.29 Blob.h程序代碼
16.29 shared_ptr2.h程序代碼
16.29 測試程序代碼 -
練習16.30
練習16.29中已經驗證 -
練習16.31
編譯器可能會去掉DebugDelete類對象和相關函數,替換爲對應的輸出語句和釋放操作 -
練習16.32
編譯器用傳遞給函數模板的實參來推斷模板實參,並可能發生兩種類型轉換 -
練習16.33
- const引用和指針的轉換
- 數組或函數指針的轉換
-
練習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 *);
- 練習16.50
16.50 程序代碼
程序輸出的結果是:
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
如果對於之前沒特例化的版本來講,是和之前函數匹配規則不一樣
但是特例化的版本不會提高優先級,因此不會影響正常函數的匹配規則