c++ primer第五版----學習筆記(十六)Ⅱ
部分習題解答:
16.1: 當呼叫template時,編譯器使用實參的型別來確定繫結到模板引數T的型別,之後編譯器利用推斷出的模板引數來例項化一個特定版本的函式 16.2:
#ifndef COMPARE_H
#define COMPARE_H
template <typename T>
int Compare(const T &val1, const T &val2)
{
if (val1 < val2)
{
return 1;
}
else
return 0;
}
#endif // ! COMPARE_H
//test.cpp #include <iostream> #include "Compare.h" using namespace std; int main(int argc, char **argv) { cout << Compare(5, 6) << endl; system("pause"); return 0; }
16.3:
Sales_data未定義“<”運算子
16.4:
#ifndef FIND_H #define FIND_H template <typename U, typename T> bool Find(const U &it1, const U &it2, const T &val) { auto it3 = it1; //傳入引數為const,需要建立一個臨時副本 for (; it3 != it2; ++it3) { if (*it3 == val) { return true; } } return false; } #endif // ! FIND_H
//test.cpp #include <iostream> #include <vector> #include <list> #include <string> #include "Find.h" using namespace std; int main(int argc, char **argv) { vector<int> vec = { 1,2,4,6,7,4,3,0,5 }; if (Find(vec.begin(), vec.end(), 5)) { cout << "the number has been found!" << endl; } else cout << "not found" << endl; list<string> lst = { "ad","sad","beautiful" }; if (Find(lst.begin(), lst.end(), "sad")) { cout << "the string has been found!" << endl; } else cout << "not found" << endl; system("pause"); return 0; }
16.5:
#ifndef PRINT_H
#define PRINT_H
template <typename T>
void Print(const T &arr)
{
for (auto elem : arr)
{
cout << elem << endl;
}
}
#endif // ! PRINT_H
//test.cpp
#include <iostream>
#include <string>
#include "Print.h"
using namespace std;
int main(int argc, char **argv)
{
string arr[5] = { "ad", "acs","night","dark","eye"};
Print(arr);
system("pause");
return 0;
}
16.6:
begin()是一個模板函式,接受一個容器的引用,返回指向容器第一個元素的迭代器 end()返回容器尾元素的下一個位置的迭代器
#ifndef BEGIN_END_H
#define BEGIN_END_H
template <typename T, size_t size>
T* begin(const T (&arr)[size])
{
return arr;
}
template <typename T, size_t size>
T* end(const T(&arr)[size])
{
return (arr + size);
}
#endif // ! BEGIN_END_H
//test.cpp
#include <iostream>
#include "Begin_end.h"
using namespace std;
int main(int argc, char **argv)
{
int arr[3] = { 0,1,2 };
cout << *(begin(arr)) << endl;
cout << *(end(arr) - 1) << endl;
system("pause");
return 0;
}
16.7:
#ifndef ARRAY_SIZE_H
#define ARRAY_SIZE_H
template <typename T, unsigned N>
size_t array_size(const T(&arr)[N])
{
return N;
}
#endif // ! ARRAY_SIZE_H
//test.cpp
#include <iostream>
#include "Array_size.h"
using namespace std;
int main(int argc, char **argv)
{
int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
cout << "Array_size : " << array_size(arr) << endl;
system("pause");
return 0;
}
16.8:
因為大多數型別定義了“!=”而未定義“<”運算子
16.9: 函式模板:用來生成特定型別的函式例項 類模板:用來生成類的藍圖 16.10: 使用顯示模板實參重寫該模板,將模板引數T的每個例項替換為給定的模板實參 16.11: 在類作用域內定義不需要新增實參列表 ListItem必須新增實參列表例項化成一個類才是一個型別
16.12:
#ifndef BLOB_H_BLOBPTR
#define BLOB_H_BLOBPTR
#include <iostream>
#include <vector>
#include <memory>
#include <initializer_list>
using namespace std;
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T> class Blob {
//宣告友元
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
public:
typedef typename vector<T>::size_type size_type;
//建構函式
Blob() :
data(make_shared<vector<T>>()) {}
Blob(initializer_list<T> il) :
data(make_shared<vector<T>>(il)) {}
bool empty() const { return data->empty(); }
size_type size() const { return data->size(); }
BlobPtr<T> begin() { return BlobPtr<T>(*this, 0); }
BlobPtr<T> end() { return BlobPtr<T>(*this, data->size()); }
T& front();
T& back();
const T& front() const;
const T& back() const;
T& at(size_type);
const T& at(size_type) const;
void push_back(const T &val) { data->push_back(val); }
void push_back(T &&val) { data->push_back(std::move(val)); }
void pop_back(); //過載運算子
T& operator[]( size_type i );
const T& operator[]( size_type i ) const;
private: //資料成員
std::shared_ptr<std::vector<T>> data; //輔助函式
void check( size_type, const std::string& ) const;
};
template <typename T>
void Blob<T>::check( size_type n, const std::string &msg ) const
{
if( n >= size() )
throw std::out_of_range( msg );
}
template <typename T>
T& Blob<T>::front()
{
check( 0, "front on empty Blob" );
return data->front();
}
template <typename T>
const T& Blob<T>::front() const
{
check( 0, "front on empty Blob" );
return data->front();
}
template <typename T>
T& Blob<T>::back()
{
check( 0, "back on empty Blob" );
return data->back();
}
template <typename T>
const T& Blob<T>::back() const
{
check( 0, "back on empty Blob" );
return data->back();
}
template <typename T>
void Blob<T>::pop_back()
{
check( 0, "pop_back on empty Blob" );
data->pop_back();
}
template <typename T>
T& Blob<T>::at( size_type i )
{
check( i, "subscript out of range" );
return ( *data )[ i ];
}
template <typename T>
const T& Blob<T>::at( size_type i ) const
{
check( i, "subscript out of range" );
return ( *data )[ i ];
}
template <typename T>
T& Blob<T>::operator[]( size_type i )
{
check( i, "subscript out of range" );
return ( *data )[ i ];
}
template <typename T>
const T& Blob<T>::operator[]( size_type i ) const
{
check( i, "subscript out of range" );
return ( *data )[ i ];
}
//友元運算子定義
template <typename T>
bool operator==( const Blob<T> &lhs, const Blob<T> &rhs )
{
if( lhs.size() != rhs.size() )
return false;
for( size_t i = 0; i != lhs.size(); ++i )
if( lhs[i] != rhs[i] )
return false;
return true;
}
template <typename T>
bool operator==( const BlobPtr<T>&, const BlobPtr<T>& );
template <typename T> class BlobPtr{
friend bool operator==<T>( const BlobPtr<T>&, const BlobPtr<T>& );
public:
BlobPtr(): curr( 0 ) { }
BlobPtr( Blob<T> &a, std::size_t sz = 0 ): wptr( a.data ), curr( sz ) { }
//公共介面
T& operator[]( std::size_t i ){
auto ret = check( i, "subscript out of range" );
return ( *ret )[ i ];
}
const T& operator[]( std::size_t i ) const{
auto ret = check( i, "subscript out of range" );
return ( *ret )[ i ];
}
T& operator*() const
{
auto ret = check( curr, "dereference past end" );
return ( *ret )[ curr ];
}
T* operator->() const
{
return & this->operator*();
}
BlobPtr& operator++();
BlobPtr& operator--();
BlobPtr operator++(int);
BlobPtr operator--(int);
private:
//資料成員
std::weak_ptr<std::vector<T>> wptr;
std::size_t curr;
//輔助函式
std::shared_ptr<std::vector<T>> check( std::size_t, const std::string& ) const;
};
template <typename T>
bool operator==( const BlobPtr<T> &lhs, const BlobPtr<T> &rhs )
{
return lhs.wptr.lock().get() == rhs.wptr.lock().get() && lhs.curr == rhs.curr;
}
template <typename T>
bool operator!=( const BlobPtr<T> &lhs, const BlobPtr<T> &rhs )
{
return !( lhs == rhs );
}
template <typename T>
std::shared_ptr<std::vector<T>>BlobPtr<T>::check( std::size_t i, const std::string &msg ) const
{
auto ret = wptr.lock();
if( !ret )
throw std::runtime_error( "unbound BlobPtr" );
if( i >= ret->size() )
throw std::out_of_range( msg );
return ret;
}
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator++()
{
check( curr, "increment past end" );
++curr;
return *this;
}
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator--()
{
--curr;
check( curr, "decrement past begin" );
return *this;
}
template <typename T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{
auto ret = *this; ++*this;
return ret;
}
template <typename T>
BlobPtr<T> BlobPtr<T>::operator--(int)
{
auto ret = *this;
--*this;
return ret;
}
#endif // ! BLOB_H_BLOBPTR
16.13: 為每個BlobPtr例項與用相同型別例項化的運算子建立起一對一的友好關係 ==運算子使用友元關係,因為要訪問到BlobPtr的私有成員 !=運算子不需要友元關係,它可以委託operator==完成任務 16.14、16.15:
#ifndef SCREEN_H
#define SCREEN_H
#include <iostream>
#include <string>
using namespace std;
template <unsigned H, unsigned W> class Screen;
template <unsigned H, unsigned W>
ostream& operator<<(ostream&, Screen<H, W>&);
template <unsigned H, unsigned W>
istream& operator>>(istream&, Screen<H, W>&);
template <unsigned H, unsigned W> class Screen {
//友元宣告
friend ostream& operator<<(ostream&, Screen<H, W>&);
friend istream& operator>>(istream&, Screen<H, W>&);
public:
//類型別名
typedef string::size_type pos;
//建構函式
Screen(char c = ' '):
contents(H * W, c) {}
//介面成員
char get() const { return contents[cursor]; } //讀取游標處的字元
char get(pos row, pos col) const {
auto ret = check(row, col);
return contents[ret];
}
Screen& set(char ch) { contents[cursor] = ch; return *this; }
Screen& set(pos row, pos col, char ch)
{
auto ret = check(row, col);
contents[cursor] = ch;
return *this;
}
Screen& move(pos row, pos col) { cursor = check(row, col); return *this; }
//輸出函式的兩種形式,根據物件是否是const呼叫不同的display函式
Screen& display(ostream &os) {
do_display(os);
return *this;
}
const Screen& display(ostream &os) const {
do_display(os);
return *this;
}
private:
//資料成員
pos cursor = 0;
string contents;
//判斷是否越界
pos check(pos row, pos col) const {
if (row >= H)
throw out_of_range("invalid row");
if (col >= W)
throw out_of_range("invalid column");
return row * W + col;
}
//顯示函式
void do_display(ostream &os)
{
for (auto i = 0; i < H; ++i)
{
for (auto j = 0; j < W; ++j)
{
os << contents[i * W + j];
}
os << endl;
}
}
};
template <unsigned H, unsigned W>
ostream& operator<<(ostream &os, Screen<H, W> &scr)
{
scr.do_display(os);
return os;
}
template <unsigned H, unsigned W>
istream& operator>>(istream &is, Screen<H, W> &scr)
{
string item;
is >> item;
scr.contents = item.substr(0, H * W);
return is;
}
#endif // ! SCREEN_H
//test.cpp
#include <iostream>
#include "Screen.h"
using namespace std;
int main(int argc, char **argv)
{
Screen<5, 5> myScreen('#');
myScreen.move(4, 0).set('*');
cout << myScreen.get(4, 0) << endl;
myScreen.display(cout);
system("pause");
return 0;
}
16.16:
#ifndef VEC_H
#define VEC_H
#include <memory>
#include <utility>
#include <initializer_list>
#include <string>
using namespace std;
template <typename T> class Vec {
public:
//預設建構函式
Vec() :
elements(nullptr), first_free(nullptr), cap(nullptr) { }
//其他建構函式
Vec(initializer_list<T>&);
//拷貝建構函式
Vec(const Vec&);
//解構函式
~Vec();
//拷貝賦值運算子
Vec& operator=(const Vec&);
void push_back(const T &); //拷貝元素
size_t size() const { return first_free - elements; } //存有元素的長度
size_t capacity() const { return cap - elements; } //分配的記憶體
void resize(size_t n); //
void reserve(size_t n);
T* begin() const { return elements; }
T* end() const { return first_free; }
private:
//資料成員
static allocator<T> alloc; //分配元素
T *elements; //指向陣列首元素的指標
T *first_free; //指向陣列第一個空閒元素的指標
T *cap; //指向陣列尾後位置的指標
//工具函式
void chk_n_alloc(); //判斷是否有空閒空間容納新元素
pair<T*, T*>
alloc_n_copy(const T*, const T*);
void free(); //銷燬元素並釋放記憶體
void reallocate(); //獲得更多記憶體並拷貝已有元素
void reallocate(size_t n);
};
//注意:靜態成員的類外定義。
template <typename T>
allocator<T> Vec<T>::alloc;
//建構函式實現
template <typename T>
inline
Vec<T>::Vec(initializer_list<T> &ls) {
auto newdata = alloc_n_copy(ls.begin(), ls.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
//如果沒有空間,則呼叫reallocate分配更多記憶體。
template <typename T>
inline void Vec<T>::chk_n_alloc(void) {
if (size() == capacity())
reallocate();
}
//分配記憶體,並拷貝一個給定範圍中的元素
template <typename T>
pair<T*, T*>
Vec<T>::alloc_n_copy(const T *b, const T *e)
{
auto data = alloc.allocate(e - b);
return { data, uninitialized_copy(b, e, data) };
}
//會銷燬構造的元素並釋放記憶體
template <typename T>
void Vec<T>::free() {
//不能傳遞給deallocate一個空指標
if (elements) {//逆序銷燬舊元素
for (auto p = first_free; p != elements; /* 空 */)
alloc.destroy(--p);
alloc.deallocate(elements, cap - elements);
}
}
/*
void StrVec::free(){
if (elements){
for_each(elements,first_free,[this](string &rhs) { alloc.destory(&rhs);});
alloc.deallocate(elements,cap-elements);
}
}
*/
template <typename T>
Vec<T>::Vec(const Vec &sv) {
auto newdata = alloc_n_copy(sv.begin(), sv.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
template <typename T>
Vec<T>::~Vec() {
free();
}
template <typename T>
Vec<T>& Vec<T>::operator=(const Vec &sv) {
auto newdata = alloc_n_copy(sv.begin(), sv.end());
free();
elements = newdata.first;
first_free = cap = newdata.second;
return *this;
}
template <typename T>
void Vec<T>::push_back(const T &s) {
chk_n_alloc(); //確保有空間容納新元素
//在first_free指向的元素中構造s的副本
alloc.construct(first_free++, s);
}
template <typename T>
void Vec<T>::reallocate() {
//我們將分配當前大小兩倍的記憶體空間
auto newcapacity = (size() ? 2 * size() : 1);
//分配新記憶體
auto newdata = alloc.allocate(newcapacity);
//將資料從舊記憶體移動到新記憶體
auto dest = newdata; //指向新陣列中下一個空閒位置
auto elem = elements; //指向舊陣列中下一個元素
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
free(); //一旦我們移動完元素就釋放舊記憶體空間
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
template <typename T>
void Vec<T>::reallocate(size_t n) {
auto newdata = alloc.allocate(n);
auto dest = newdata;
auto elem = elements;
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
free();
elements = newdata;
first_free = dest;
cap = newdata + n;
}
template <typename T>
void Vec<T>::resize(size_t n) {
if (n > size()) {
while (size() < n)
push_back("");
}
else if (n < size()) {
while (size() > n)
alloc.destroy(--first_free);
}
}
template <typename T>
void Vec<T>::reserve(size_t n) {
if (n > capacity())
reallocate(n);
}
#endif // ! VEC_H
16.17: 在模板引數列表中,typename和class兩個關鍵字的含義相同,都是表明模板引數是一個型別 當我們使用模板型別引數通過作用域運算子來訪問成員時,如T::value_type,預設情況下,c++語言假定通過作用域運算子訪問的是名字而不是型別。因此我們希望使用一個模板型別引數的型別成員,就必須通過使用關鍵字typename顯示告訴編譯器該名字是一個型別 16.18: (a)錯誤,缺少typename,改為:template <typename T, typename U, typename V> void f1(T, U, V); (b)錯誤,模板型別名不能作為變數名,改為:template <typename T> T f2(T &); (c)錯誤,內聯位置錯誤,改為:template <typename T> inline T foo(T, unsigned int*); (d)錯誤,缺少返回型別,改為:template <typename T> T f4(T, T); (e)合法 16.19:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
void print(ostream &os, const T &vec)
{
for (typename T::size_type i = 0; i < vec.size(); ++i)
{
os << vec[i] << " ";
}
os << endl;
}
int main(int argc, char **argv)
{
vector<int> vec{ 1,2,3,4,5,6 };
print(cout, vec);
system("pause");
return 0;
}
16.20:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
void print(ostream &os, const T &vec)
{
for (auto it = vec.begin(); it != vec.end();++it)
{
os << *it << " ";
}
os << endl;
}
int main(int argc, char **argv)
{
vector<int> vec{ 1,2,3,4,5,6 };
print(cout, vec);
system("pause");
return 0;
}
16.21:
#ifndef DEBUGDELETE_H
#define DEBUGDELETE_H
#include <iostream>
using namespace std;
class DebugDelete {
public:
DebugDelete(ostream &s = cerr): os(s) { }
template <typename T>
void operator()(T *p) const
{
os << "delete unique_ptr" << endl;
delete p;
}
private:
ostream & os;
};
#endif //DEBUGDELETE_H
//test.cpp
#include <iostream>
#include "DebugDelete.h"
using namespace std;
int main(int argc, char **argv)
{
double *p = new double;
DebugDelete d;
d(p);
int *ip = new int;
DebugDelete()(ip);
system("pause");
return 0;
}
16.22: shared_ptr過載刪除器的方式:
shared_ptr<int> n(new int,Debugdelete());
16.24:
#ifndef BLOB_H
#define BLOB_H
template <typename T> class Blob {
template <typename It> Blob(It &b, It &e);
//....
};
template <typename T>
template <typename It>
Blob<T>::Blob(It &b, It &e) :
data(make_shared<vector<T>>(b,e)) { }
#endif //BLOB_H
16.25: 例項化宣告class vector 例項化定義class vector 16.26: 不可以,因為當我們顯示例項化vector<NoDefault>時,編譯器會例項化vector的所有成員函式,包括它接受容器大小引數的建構函式。vector的這個建構函式會使用元素的預設建構函式來對元素進行值初始化,而NoDefault沒有預設建構函式,從而導致編譯器報錯 16.27: (a)char例項化了模板stack (b)double例項化了模板stack (c)int例項化了模板stack (d)已有該例項化的定義,不需要再例項化 (e)已有該例項化的定義,不需要再例項化 (f)string例項化了模板stack
16.28:shared_ptr.......
#ifndef MY_SHARED_PTR_H
#define MY_SHARED_PTR_H
template <typename T> class My_shared_ptr {
public:
My_shared_ptr() :
p(nullptr), use(nullptr) {}
//建構函式
My_shared_ptr(T &pt) :
p(pt), use(new size_t(1)) {}
//拷貝建構函式
My_shared_ptr(const My_shared_ptr &msp):
p(msp.p), use(msp.use) {
if (use) ++*use;
}
//拷貝賦值運算子
My_shared_ptr& operator=(const My_shared_ptr&);
//解構函式
~My_shared_ptr();
//介面函式
T& operator*() { return *p; }
T& operator*() const { return *p; }
private:
T * p; //指標
size_t * use; //儲存共享該物件的指標數目(即為引用計數)
};
//拷貝賦值運算子
template <typename T>
My_shared_ptr<T>& My_shared_ptr<T>::operator=(const My_shared_ptr &rhs)
{
if (rhs.use) //如果賦值的右值的引用計數不為0則增加其引用計數
++*(rhs.use);
if (use && --*use == 0) //如果賦值的左值的引用計數不為0但遞減引用計數為0則刪除該指標
{
delete p;
delete use;
}
p = rhs.p;
use = rhs.use;
return *this;
}
//解構函式
template <typename T>
My_shared_ptr<T>::~My_shared_ptr()
{
if (use && --*use == 0)
{
delete p;
delete use;
}
}
#endif // ! MY_SHARED_PTR_H
16.31:
unique_ptr是儲存刪除器函式的指標,所以需要一次跳轉操作,並不會內聯而是跳轉
16.32: 在模板實參推斷過程中,編譯器使用函式呼叫中的實參型別來尋找模板實參,用這些模板實參生成的函式版本與給定的函式呼叫匹配
16.33:
const轉換、陣列或函式指標轉換
16.34: 該題中的字串並不是string型別,而是根據長度判斷的char[n]型別,長度不同型別也不同,所以(a)不合法,(b)合法
16.35:
(a):合法,第一個為char,即為T,第二個為char [1],可以進行型別轉換
(b):合法,T為double,clac第二個引數為普通型別的int,可以進行算數型別轉換
(c):不合法,一個char,一個char[1]
(d):不合法,一個double一個float,無法進行型別轉換 16.36:
(a):合法,T為 int*
(b):合法,T1和T2都為int*
(c):合法,T為const int*
(d):合法,T1和T2都為const int*
(e):不合法,首先需要判斷實參的型別是否相同,再判斷型別是否可轉換,兩引數一個為const一個非const
(f):合法,T1為int*, T2的型別為const int*
16.37: 雖然max兩個實參不同,但是我們可以通過顯示的模版實參進行修改,指定了引數之後,傳入引數可以不同,但是轉換結果必須相同,可以進行型別轉換
max<int>(a,b);//將b的型別強制轉換為int
16.38: make_shared接收的實參是一個模板引數包,返回型別是一個shared_ptr<_Ty>,_Ty是一個模板引數,不指定顯示模板實參無法推斷其返回型別 16.39: char[]型別轉換為string
compare<string>("a","abb");
16.40:
函式合法。
但有兩個問題:
序列元素型別必須支援+運算子
*beg + 0是右值,因此fcn3的返回型別被推斷為元素型別的常量引用
16.41:
#ifndef SUM_H
#define SUM_H
template <typename T>
auto sum(const T&a, const T&b)->decltype(a + b)
{
return a + b;
}
#endif //SUM_H
#include<iostream>
#include "Sum.h"
using namespace std;
int main(int argc, char **argv)
{
int a = 123353;
int b = 124568;
cout << sum(a,b) << endl;
system("pause");
return 0;
}
16.42-16.45:
#include <iostream>
#include <vector>
using namespace std;
template <typename T> void g(T&& val){}
template <typename T> void g1(T val) {}
template <typename T> void g2(const T&) {}
template <typename T> void g3(T&& val) { vector<T> v; }
int main(int argc, char **argv)
{
int i = 0;
const int ci = i;
//16.42
g(i); //void g<int &>(int &val)
g(ci); //void g<const int &>(const int &val)
g(i * ci); //void g<int> (int &&val)
//16.43
g(i = ci); //賦值表示式是一個左值,void g<int &>(int &val)
//16.44
g1(i); //void g1<int>(int val)
g1(ci); //頂層const被忽略,void g1<int>(int val)
g1(i * ci); //void g1<int>(int val)
g2(i); //void g2<int>(const int&)
g2(ci);//void g2<int>(const int&)
g2(i * ci); //void g2<int>(const int&)
//16.45
g3(42);//42為右值,void g2<int> (int &&val)
g3(i); //當對一個int型別變數呼叫g3時,T為int &,但vector的元素不能是引用,因此編譯失敗
system("pause");
return 0;
}
16.46: 將elem的元素移動到dest空間(將資料從舊的記憶體空間移動到新記憶體空間)
16.47:
#ifndef UP_DOWN_H
#define UP_DOWN_H
template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
f(std::forward<T2>(t2), std::forward<T1>(t1));
}
#endif // ! UP_DOWN_H
#include <iostream>
#include <utility>
#include "Up_down.h"
using namespace std;
void f(int &i, int &&j)
{
cout << i << " " << j << endl;
}
int main(int argc, char **argv)
{
int i = 5;
flip(f, 42, i);
system("pause");
return 0;
}
16.48:
#ifndef DEBUG_REP_H
#define DEBUG_REP_H
#include <iostream>
#include <string>
using namespace std;
template <typename T> string debug_rep(const T &t)
{
cout << "const T&: " << endl;
return t.str();
}
template <typename T> string debug_rep(T *t)
{
cout << "T *t: " << endl;
return t.str();
}
string Debug_rep(const string&t)
{
cout << "普通版本函式:" << t << endl;
return t.str();
}
string Debug_rep(char *t)
{
cout << "普通版本函式(接受char*):" << t << endl;
return Debug_rep(string(t));
}
#endif // ! DEBUG_REP_H
16.49、16.50:
//16.49.h
#ifndef TEST_H
#define TEST_H
template <typename T> void f(T t)
{
cout << "f : T t:" << t << endl;
}
template <typename T> void f(const T *t)
{
cout << "f : const T *t:" << t << endl;
}
template <typename T> void g(T t)
{
cout << "g : T t:" << t << endl;
}
template <typename T> void g( T *t)
{
cout << "g : T *t:" << t << endl;
}
#endif // ! TEST_H
#include <iostream>
#include "16.49.h"
using namespace std;
template <typename T> void f(T);
template <typename T> void f(const T*);
template <typename T> void g(T);
template <typename T> void g(T *);
int main(int argc, char **argv)
{
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42);//呼叫g(T t)
g(p); //呼叫g(T *t)
g(ci);//呼叫g(T t)
g(p2); //呼叫g(T *t)
f(42);//呼叫f(T t)
f(p); //呼叫f(T t)
f(ci);//呼叫f(T t)
f(p2);//呼叫f(const T*)
system("pause");
return 0;
}
16.51、16.52:
#include <iostream>
using namespace std;
template <typename T, typename...Args>
void foo(const T &t, const Args&...rest)
{
cout << sizeof...(Args) << endl;
cout << sizeof...(rest) << endl;
}
int main(int argc, char **argv)
{
int i = 0;
double d = 3.14;
string s = "how now brown cow";
foo(i, s, 42, d); //3 3
foo(s, 42, "hi"); //2 2
foo(d, s); //1 1
foo("hi");//0 0
system("pause");
return 0;
}
16.53:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
ostream &print(ostream &os, const T &t)
{
return os << t; //包中最後一個元素之後不列印分隔符
}
template <typename T, typename...Args>
ostream &print(ostream &os, const T &t, const Args&...rest)
{
os << t << ", "; //列印第一個實參
return print(os, rest...); //遞迴呼叫,列印其他實參
}
int main(int argc, char **argv)
{
int i = 0;
double d = 3.14;
float m = 4.0;
string s = "how now brown cow";
print(cout, i, d);
cout << endl;
print(cout, i, d, m);
cout << endl;
print(cout, i, d, m, "nu", "ml", s);
cout << endl;
system("pause");
return 0;
}
16.54:
缺少“<<”的定義
16.55:
在其後呼叫,先前的print版本找不到非可變引數版本的print函式,造成無限遞迴 16.56:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
template <typename T> string debug_rep(const T &t);
template <typename T> string debug_rep(T *p);
string debug_rep(const string &s);
string debug_rep(char *p);
string debug_rep(const char *p);
template <typename T> string debug_rep(const T &t)
{
ostringstream ret;
ret << t;
return ret.str();
}
template <typename T> string debug_rep(T *p)
{
ostringstream ret;
ret << "pointer: " << p;
if (p)
ret << " " << debug_rep(*p);
else
ret << " null pointer";
return ret.str();
}
string debug_rep(const string &s)
{
return '"' + s + '"';
}
string debug_rep(char *p)
{
return debug_rep(string(p));
}
string debug_rep(const char *p)
{
return debug_rep(string(p));
}
template <typename T>
ostream &print(ostream &os, const T &t)
{
return os << t; //包中最後一個元素之後不列印分隔符
}
template <typename T, typename...Args>
ostream &print(ostream &os, const T &t, const Args&...rest)
{
os << t << ", "; //列印第一個實參
return print(os, rest...); //遞迴呼叫,列印其他實參
}
template <typename ...Args>
ostream &errorMsg(ostream &os, const Args&...rest)
{
return print(os, debug_rep(rest)...);
}
int main(int argc, char **argv)
{
string str = "c++";
errorMsg(cout, str, "prime", 4, 4.8, "r");
system("pause");
return 0;
}
16.57: error_msg只能接受string型別的形參或者能轉換成string的實參;errorMsg能接受各個不同型別的實參,但errorMsg的編寫較為繁瑣
16.58:
template <typename...Args>
inline
void StrVec::emplace_back(Args...args)
{
chk_n_alloc();
alloc.construct(first_free++, std::forward<Args>(args)...);
}
16.59:
s是一個左值,經過std::forward<string>(s),將一個型別為string&的實參傳遞給string的建構函式構造一個新元素 16.60: 接受可變引數模板,轉發其引數初始化一個內存於記憶體空間,返回一個shared_ptr 16.61:
template <typename T, typename ...Args>
shared_ptr<T> make_shared(Args&&...args)
{
return shared_ptr<T>(new T(std::forward<Aegs>(args)));
}
16.62:
#ifndef SALES_DATA_H_INCLUDED
#define SALES_DATA_H_INCLUDED
#include<iostream>
class Sales_data{
//友元函式
friend struct std::hash<Sales_data>;
friend std::istream& operator >> ( std::istream&, Sales_data& );
friend std::ostream& operator << ( std::ostream&, const Sales_data& );
friend bool operator < ( const Sales_data&, const Sales_data& );
friend bool operator == ( const Sales_data&, const Sales_data& );
friend Sales_data add( Sales_data &rhs, Sales_data &lhs );
friend std::istream& read( std::istream& in, Sales_data &item );
friend std::ostream& print( std::ostream &out, const Sales_data &rhs );
public: //建構函式
/* Sales_data( const std::string &book, const unsigned units, const double sellingprice, const double saleprice ) :
bookNo( book ), units_sold( units ), selling_price( sellingprice ), sale_price( saleprice )
{
if( selling_price )
discount = sale_price / selling_price;
std::cout << "四個引數的建構函式的函式體" << std::endl;
}
*/
//委託建構函式:
/* Sales_data(): Sales_data( "", 0, 0, 0 ) { std::cout << "無引數的建構函式的函式體" << std::endl; }
Sales_data( const std::string &s ) : Sales_data( s, 0, 0, 0 ) { std::cout << "接受字串的建構函式的函式體" << std::endl; };
Sales_data( std::istream &is ) : Sales_data() { read( is, *this ); std::cout << "接受輸入流的建構函式的函式體" << std::endl; }
*/
Sales_data() = default;
Sales_data( const std::string &book ): bookNo( book ) { }
Sales_data( const std::string &book, const unsigned units, const double sellingprice, const double saleprice );
Sales_data( std::istream &is ) { is >> *this; }
public:
Sales_data& operator += ( const Sales_data& );
std::string isbn() const { return bookNo; }
Sales_data& combine( const Sales_data &rhs );
private:
std::string bookNo;
unsigned units_sold = 0;
double selling_price = 0.0;
double sale_price = 0.0;
double discount = 0.0;
};
inline bool compareIsbn( const Sales_data&lhs, const Sales_data&rhs )
{
return lhs.isbn() == rhs.isbn();
}
Sales_data operator + ( const Sales_data&, const Sales_data& );//宣告
//友元函式定義
inline bool operator == ( const Sales_data &lhs, const Sales_data &rhs )
{
return lhs.units_sold == rhs.units_sold && lhs.sale_price == rhs.sale_price &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != ( const Sales_data &lhs, const Sales_data &rhs )
{
return !( lhs == rhs );
}
inline bool operator<( const Sales_data &lhs, const Sales_data &rhs )
{
return lhs.bookNo < rhs.bookNo;
}
inline Sales_data add( Sales_data &rhs, Sales_data &lhs )
{
Sales_data sum = rhs;
sum.combine( lhs );
return sum;
}
inline std::ostream& print( std::ostream &out, const Sales_data &rhs )
{
out << rhs.bookNo << " " << rhs.units_sold << " " << rhs.selling_price << " "
<< rhs.sale_price << " " << rhs.discount;
return out;
}
inline std::istream& read( std::istream& in, Sales_data &item )
{
in >> item.bookNo >> item.units_sold >> item.selling_price >> item.sale_price;
return in;
}
//建構函式
Sales_data::Sales_data( const std::string &book, unsigned units, double sellingprice, double saleprice )
{
bookNo = book;
units_sold = units;
selling_price = sellingprice;
sale_price = saleprice;
if( selling_price != 0 )
discount = sale_price / selling_price;
}
//成員函式
Sales_data& Sales_data::operator += ( const Sales_data &rhs )
{
sale_price = ( rhs.sale_price * rhs.units_sold + sale_price * units_sold )
/( rhs.units_sold + units_sold );
selling_price = ( rhs.selling_price * rhs.units_sold + selling_price * units_sold )
/( rhs.units_sold + units_sold );
units_sold += rhs.units_sold;
if( sale_price != 0 )
discount = sale_price / selling_price;
return *this;
}
Sales_data operator + ( const Sales_data &lhs, const Sales_data &rhs )
{
Sales_data tmp( lhs );
tmp += rhs;
return tmp;
}
std::istream& operator >> ( std::istream &in, Sales_data &s )
{
in >> s.bookNo >> s.units_sold >> s.selling_price >> s.sale_price;
if( in && s.selling_price != 0 )
s.discount = s.sale_price / s.selling_price;
else
s = Sales_data();
return in;
}
std::ostream& operator << ( std::ostream &out, const Sales_data &s )
{
out << s.isbn() << " " << s.units_sold << " "
<< s.selling_price << " " << s.sale_price << " " << s.discount;
return out;
}
Sales_data& Sales_data::combine( const Sales_data &rhs )
{
units_sold += rhs.units_sold;
sale_price = ( units_sold * sale_price + rhs.units_sold * rhs.sale_price )
/ ( units_sold + rhs.units_sold );
if( selling_price != 0 )
discount = sale_price / selling_price;
return *this;
}
namespace std{
template <> struct hash<Sales_data>{
typedef size_t result_type;
typedef Sales_data argument_type;
size_t operator()( const Sales_data & s ) const;
};
size_t hash<Sales_data>::operator() ( const Sales_data &s ) const{
return hash<string>()( s.bookNo ) ^
hash<unsigned>() ( s.units_sold ) ^
hash<double>() ( s.selling_price ) ^
hash<double>() ( s.sale_price );
}
}
#endif // SALES_DATA_H_INCLUDED
#include<iostream>
#include<unordered_set>
#include"Sales_data.h"
using namespace std;
int main()
{
unordered_multiset<Sales_data> SDset;
Sales_data obj1( "C++Primer", 50, 128, 68 );
Sales_data obj2( "C primer plus", 40, 98, 52 );
Sales_data obj3( obj1 );
SDset.insert( obj1 );
SDset.insert( obj2 );
SDset.insert( obj3 );
for( const auto &sd : SDset )
cout << sd << endl;
return 0;
}
16.63、16.64:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
void count_num(const vector<T> &vec, const T &val)
{
int cnt = 0;
for (auto it = vec.begin(); it != vec.end(); ++it)
{
if (*it == val)
{
++cnt;
}
}
cout <<"出現的次數為:" << cnt << endl;
}
template <>
void count_num(const vector<const char*> &vec, const char* const &val)
{
int cnt = 0;
for (auto it = vec.begin(); it != vec.end(); ++it)
{
if (strcmp((*it), val) == 0) {
++cnt;
}
}
cout << "出現的次數為:" << cnt << endl;
}
int main(int argc, char **argv)
{
vector<double> vec1{ 1.2,2.3,3.4,4.5,5.6,6.7 };
count_num(vec1, 2.3);
vector<int> vec2{ 1,2,3,3,5,6 };
count_num(vec2, 3);
vector<string> vec3{ "a","ax","ax","ax","axca" };
string s = "ax";
count_num(vec3, s);
vector<const char*> vec4{ "1","12","123","1234" };
const char* c = "123";
count_num(vec4, c);
system("pause");
return 0;
}
16.65:
template <typename T> string debug_rep(const T &t)
{
ostringstream ret;
ret << t;
return ret.str();
}
template<>
string debug_rep(char * const &p)
{
return debug_rep(string(p));
}
template<>
string debug_rep(const char * const &p)
{
return debug_rep(string(p));
}
16.66: 優點:特例化只是一個例項,並不是過載,所以會減少過載函式的資源消耗 缺點:當有函式過載時,優先順序會低於過載函式 16.67: 特例化的本質是例項化一個模板,而非過載它,因此特例化並不影響函式匹配