c++ primer 第十六章習題
c++ primer 第十六章習題
練習16.1 例項化是指傳遞給模板相應的模板引數,使其生成對應型別的函式體或是型別定義。
練習16.2
#include <iostream> #include <string> #include <vector> #include "Sales_data.cc" using namespace std; template <typename T> int compare(const T& a, const T& b) { if (less<T>()(a,b)) return -1; if (less<T>()(b,a)) return 1; return 0; } int main() { int a = 1, b = 2; double c = 1.0, d = 3.0; Sales_data s1("nihao"), s2("haha"); cout << compare(a,b) <<endl; cout << compare(c,d) <<endl; cout << compare(s1,s2) <<endl; return 0; }
練習16.4
#include <iostream> #include <string> #include <vector> #include <list> using namespace std; template <typename T,typename ITER> ITER find(const ITER& begin, const ITER& end, T value) { ITER tmp = begin; while(tmp != end) { if(*tmp == value) return tmp; tmp++; } return end; } int main() { vector<int> a = {1,2,3,4,5}; list<string> l = {"heh", "nihao","wawa","world"}; auto iter1 = find(a.begin(), a.end(), 3); if(iter1 != a.end()) cout << "find: "<<*iter1<<endl; auto iter2 = find(l.begin(), l.end(), "world"); if(iter2 != l.end()) cout << "find: "<<(*iter2)<<endl; return 0; }
練習16.5
template <typename T, unsigned N>
void print(T (&arr)[N]) {
for(T a : arr)
cout << a << endl;
}
int main() {
int a[] = {1,2,3,4,5};
string l[] = {"heh", "nihao","wawa","world"};
print(a);
print(l);
return 0;
}
練習16.6
template <typename T, unsigned N> T* begin1(T (&arr)[N]) { return arr; } template <typename T, unsigned N> T* end1(T (&arr)[N]) { return arr+N; } int main() { int a[] = {1,2,3,4,5}; string l[] = {"heh", "nihao","wawa","world"}; cout << *begin1(a)<<endl; cout << end1(l)-begin1(l)<<endl; return 0; }
練習16.7
template<typename T, unsigned N>
constexpr unsigned size(T (&arr)[N]) {
return N;
}
練習16.8 有很多類中沒有定義<符號
練習16.9 函式模板是一個公式,針對不同型別的實參呼叫生成對應版本的函式。類模板是一個類的藍圖,不能像函式模板一樣自動推斷模板引數。使用時需要使用顯式的型別。
練習16.10 編譯器生成對應引數型別的類的定義,包括內聯的成員函式。
練習16.11 使用模板類時需要給出顯式型別。
練習16.13 一對一友元關係
練習16.14 15
#ifndef SCREEN_H
#define SCREEN_H
#include <string>
#include <iostream>
template<unsigned H, unsigned W> class Screen;
template<unsigned H, unsigned W>
std::ostream& operator<<(std::ostream& os, const Screen<H,W>&);
template<unsigned H, unsigned W>
std::istream& operator>>(std::istream& is, Screen<H,W>&);
template <unsigned H, unsigned W>
class Screen
{
public:
typedef std::string::size_type pos;
Screen() = default;
Screen(char c): contents(W*H,c) {}
char get() const {
return contents[cursor];
}
friend std::ostream& operator<<<H,W>(std::ostream& os, const Screen<H,W>& c);
friend std::istream& operator>><H,W>(std::istream& is, Screen<H,W>& c);
Screen& move(pos r, pos c);
private:
pos cursor = 0;
pos height = H, width = W;
std::string contents;
};
template<unsigned H, unsigned W>
Screen<H,W>& Screen<H,W>::move(pos r, pos c) {
cursor = r*W+c;
return *this;
}
template<unsigned H, unsigned W>
std::istream& operator>>(std::istream& is, Screen<H,W>& c) {
char a;
is >> a;
std::string tmp(H*W,a);
c.contents = tmp;
return is;
}
template<unsigned H, unsigned W>
std::ostream& operator<<(std::ostream& os, const Screen<H,W>& c) {
for(int i = 0; i < c.height; i++)
os << c.contents.substr(i*W,W);
return os;
}
#endif
練習16.14,15
#ifndef SCREEN_H
#define SCREEN_H
#include <string>
#include <iostream>
template<unsigned H, unsigned W> class Screen;
template<unsigned H, unsigned W>
std::ostream& operator<<(std::ostream& os, const Screen<H,W>&);
template<unsigned H, unsigned W>
std::istream& operator>>(std::istream& is, Screen<H,W>&);
template <unsigned H, unsigned W>
class Screen
{
public:
typedef std::string::size_type pos;
Screen() = default;
Screen(char c): contents(W*H,c) {}
char get() const {
return contents[cursor];
}
friend std::ostream& operator<<<H,W>(std::ostream& os, const Screen<H,W>& c);
friend std::istream& operator>><H,W>(std::istream& is, Screen<H,W>& c);
Screen& move(pos r, pos c);
private:
pos cursor = 0;
pos height = H, width = W;
std::string contents;
};
template<unsigned H, unsigned W>
Screen<H,W>& Screen<H,W>::move(pos r, pos c) {
cursor = r*W+c;
return *this;
}
template<unsigned H, unsigned W>
std::istream& operator>>(std::istream& is, Screen<H,W>& c) {
char a;
is >> a;
std::string tmp(H*W,a);
c.contents = tmp;
return is;
}
template<unsigned H, unsigned W>
std::ostream& operator<<(std::ostream& os, const Screen<H,W>& c) {
for(int i = 0; i < c.height; i++)
os << c.contents.substr(i*W,W);
return os;
}
#endif
練習16.15 <<過載和 >>過載為友元
練習16.17 沒有不同 需要說明型別的時候
練習16.18 (a)缺了一個typename (b)不能重用T © inline在返回值型別之前
(d) 返回值未說明 (e) 正確 但隱藏了外層的Ctype
練習16.19
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template <typename T>
void print(const T& v) {
typename T::size_type index = 0;
while(index < v.size())
cout << v[index++]<<endl;
}
int main() {
vector<string> v = {"hello","it's","me"};
print(v);
return 0;
}
練習16.20
template <typename T>
void print(const T& v) {
typename T::const_iterator iter = v.begin();
while(iter != v.end())
cout << *iter++<<endl;
}
練習16.21
#include <iostream>
#include <string>
#include <vector>
class debugDelete
{
public:
debugDelete(const std::string& p = "unique_ptr", std::ostream& o = std::cerr):s(p),os(o){};
template<typename T> void operator()(T* p) {
os << "deleting "<<p<<std::endl;
delete p;
}
private:
std::string s;
std::ostream os;
};
練習16.24
template <typename T>
template <typename It>
Blob<T>::Blob(It b, It e):
data(std::make_shared<std::vector<T>>(b, e)) { }
練習16.25 第一個是宣告外部有此例項的模板類。第二個是定義特定模板類例項。
練習16.26 不可以,因為例項化時會呼叫其建構函式。
練習16.27 TTTFFT
練習16.31 定義unique_ptr時同時輸入DebugDelete類的型別作為模板實參,然後將其例項化類中的該型別實參對應的成員賦值為DebugDelete類的物件。
練習16.32 判斷實參型別與型別名是否與模板匹配
練習16.33 1.從非const物件的引用或指標賦值給const型別的引用或指標。2.陣列型別轉為對應指標型別。
練習16.34 (a)不合法,陣列長度不匹配 (b)合法
練習16.35 TTTF
練習16.36 TTTTFT
練習16.37 可以,使用顯式實參
練習16.38 用來指定返回的共享指標的例項化型別。不指定的話無法知道需要分配的記憶體大小。
練習16.39 compare<string>(a,b)
練習16.40 合法,需要指向的型別支援與整型的加法
練習16.41
template<typename T>
auto sum(T lhs, T rhs) -> decltype( lhs + rhs)
{
return lhs + rhs;
}
練習16.42 (a) T: int& val: int& (b) const int& const int& © int int&&
練習16.43 int&
練習16.44 1、a、T為int,val為int
b、T為int,val為int,const被忽略,因為是按值傳遞
c、T為int,val為int,實參是右值,但是按值傳遞給形參
2、a、T為int,val為const int&
b、T為int,val為const int&
c、T為int&&,val為const int& &&,摺疊為const int&
練習16.45 正確,T是int。 錯誤,T是int&因此vector定義失敗。
練習16.46 從dest指標位置開始使用elem指向的物件的右值引用構造size()個。
練習16.47
template<typename F, typename T1,typename T2>
void flip(F f, T1&& t1, T2&& t2) {
f(std::forward<T2>(t2),std::forward<T1>(t1));
}
練習16.48
template<typename T>
string debug_rep(const T& t) {
ostringstream ret;
res << t;
return t.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();
}
練習16.49 前f 後 前g 後 前f 後 前g 後
練習16.51 52
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() {
vector<string> v = {"hello","it's","me"};
int a = 1;
string c = "shif";
double k = 2.0;
foo(a,v,c,k);
foo(a,v,c);
foo(a,v);
foo(a);
return 0;
}
練習16.53
template<typename T>
void print(ostream& os, const T& t) {
os << t;
}
template<typename T, typename... Args>
void print(ostream& os, const T& t, const Args& ... rest) {
os << t << ",";
print(os,rest...);
}
int main() {
int a = 1;
string c = "shif";
double k = 2.0;
print(cout,a,c,k);
return 0;
}
練習16.54 會報錯
練習16.55 會執行到引數少的無法匹配然後報錯
練習16.56
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();
}
template<typename... Args>
void error_msg(ostream& os, const Args&... args) {
print(os, debug_rep(args)...);
}
練習16.57 可變引數版本可以接收不同數量不同型別的報錯資訊但是需要遞迴。固定型別的不需要遞迴,但不夠靈活。
練習16.58
template<typename... Args>
inline
void StrVec::emplace_back(Args&&... args) {
chk_n_alloc();
allocator.construct(first_free++,std::forward<Args>(args)...);
}
練習16.59 會呼叫construct函式,construct函式會呼叫string的賦值建構函式。
練習16.60 61
template<typename T,typename... Args>
shared_ptr<T> make_shared(Args... args) {
return shared_ptr<T>(new T(std::forward<Args>(args)...));
}
練習16.62
namespace std {
class hash<Sales_data> {
typedef size_t result_type;
typedef Sales_data argument_type;
size_t operator()(const Sales_data& s) {
return hash<string>()(s.bookNo)^hash<unsigned>()(s.units_sold)^hash<double>()(s.revenue);
}
}
}
練習16.63 64
template<typename T>
size_t count(const vector<T>& v, T a) {
size_t res = 0;
for(T t : v)
if (t == a)
res++;
return res;
}
template<>
size_t count(const vector<const char*>& v, const char* a) {
size_t res = 0;
for(auto t : v)
if (strcmp(t,a) == 0)
res++;
return res;
}
int main() {
vector<double> dv = {1,2,3,4,5,6,6,2,3,2,2};
vector<int> di = {1,1,1,1,2,3,3,2,1,1};
vector<string> ds = {"hello", "hello","its","its","me"};
vector<const char*> dc = {"hello", "hello","its","its","me"};
cout << count(dv,2.0)<<endl;
cout << count(di,1)<<endl;
cout << count(ds,string("hello"))<<endl;
cout << count(dc,"hello")<<endl;
return 0;
}
練習16.65
template<>
string debug_rep(char* p) {
return debug_rep(string(p));
}
template<>
string debug_rep(const char* p) {
return debug_rep(string(p));
}
練習16.66 過載要寫的函式太多,每種型別都寫一個,但不會匹配錯誤。特例化只需要對特定型別進行單獨編寫,但是有可能無法匹配上或是忘記宣告導致呼叫錯誤的函式。
練習16.67 不會,因為模板的特例化是模板的例項而不是過載。