#include
#include
#include
#include "Sales_data.cc"
using namespace std;
template
int compare(const T& a, const T& b) {
if (less()(a,b)) return -1;
if (less()(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) <
练习16.4
#include
#include
#include
#include
using namespace std;
template
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 a = {1,2,3,4,5};
list l = {"heh", "nihao","wawa","world"};
auto iter1 = find(a.begin(), a.end(), 3);
if(iter1 != a.end())
cout << "find: "<<*iter1<
练习16.5
template
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
T* begin1(T (&arr)[N]) {
return arr;
}
template
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)<
练习16.7
template
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
#include
template class Screen;
template
std::ostream& operator<<(std::ostream& os, const Screen&);
template
std::istream& operator>>(std::istream& is, Screen&);
template
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<<(std::ostream& os, const Screen& c);
friend std::istream& operator>>(std::istream& is, Screen& c);
Screen& move(pos r, pos c);
private:
pos cursor = 0;
pos height = H, width = W;
std::string contents;
};
template
Screen& Screen::move(pos r, pos c) {
cursor = r*W+c;
return *this;
}
template
std::istream& operator>>(std::istream& is, Screen& c) {
char a;
is >> a;
std::string tmp(H*W,a);
c.contents = tmp;
return is;
}
template
std::ostream& operator<<(std::ostream& os, const Screen& 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
#include
template class Screen;
template
std::ostream& operator<<(std::ostream& os, const Screen&);
template
std::istream& operator>>(std::istream& is, Screen&);
template
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<<(std::ostream& os, const Screen& c);
friend std::istream& operator>>(std::istream& is, Screen& c);
Screen& move(pos r, pos c);
private:
pos cursor = 0;
pos height = H, width = W;
std::string contents;
};
template
Screen& Screen::move(pos r, pos c) {
cursor = r*W+c;
return *this;
}
template
std::istream& operator>>(std::istream& is, Screen& c) {
char a;
is >> a;
std::string tmp(H*W,a);
c.contents = tmp;
return is;
}
template
std::ostream& operator<<(std::ostream& os, const Screen& 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
#include
#include
using namespace std;
template
void print(const T& v) {
typename T::size_type index = 0;
while(index < v.size())
cout << v[index++]< v = {"hello","it's","me"};
print(v);
return 0;
}
练习16.20
template
void print(const T& v) {
typename T::const_iterator iter = v.begin();
while(iter != v.end())
cout << *iter++<
练习16.21
#include
#include
#include
class debugDelete
{
public:
debugDelete(const std::string& p = "unique_ptr", std::ostream& o = std::cerr):s(p),os(o){};
template void operator()(T* p) {
os << "deleting "<
练习16.24
template
template
Blob::Blob(It b, It e):
data(std::make_shared>(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
练习16.40 合法,需要指向的类型支持与整型的加法
练习16.41
template
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
void flip(F f, T1&& t1, T2&& t2) {
f(std::forward(t2),std::forward(t1));
}
练习16.48
template
string debug_rep(const T& t) {
ostringstream ret;
res << t;
return t.str();
}
template
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
void foo(const T& t, const Args& ... rest) {
cout << sizeof...(Args)< 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
void print(ostream& os, const T& t) {
os << t;
}
template
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
string debug_rep(T* p) {
ostringstream ret;
ret << "pointer: "<< p;
if (p)
ret << " "<< debug_rep(*p);
else
ret << "null pointer";
return ret.str();
}
template
void error_msg(ostream& os, const Args&... args) {
print(os, debug_rep(args)...);
}
练习16.57 可变参数版本可以接收不同数量不同类型的报错信息但是需要递归。固定类型的不需要递归,但不够灵活。
练习16.58
template
inline
void StrVec::emplace_back(Args&&... args) {
chk_n_alloc();
allocator.construct(first_free++,std::forward(args)...);
}
练习16.59 会调用construct函数,construct函数会调用string的赋值构造函数。
练习16.60 61
template
shared_ptr make_shared(Args... args) {
return shared_ptr(new T(std::forward(args)...));
}
练习16.62
namespace std {
class hash {
typedef size_t result_type;
typedef Sales_data argument_type;
size_t operator()(const Sales_data& s) {
return hash()(s.bookNo)^hash()(s.units_sold)^hash()(s.revenue);
}
}
}
练习16.63 64
template
size_t count(const vector& v, T a) {
size_t res = 0;
for(T t : v)
if (t == a)
res++;
return res;
}
template<>
size_t count(const vector& v, const char* a) {
size_t res = 0;
for(auto t : v)
if (strcmp(t,a) == 0)
res++;
return res;
}
int main() {
vector dv = {1,2,3,4,5,6,6,2,3,2,2};
vector di = {1,1,1,1,2,3,3,2,1,1};
vector ds = {"hello", "hello","its","its","me"};
vector dc = {"hello", "hello","its","its","me"};
cout << count(dv,2.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 不会,因为模板的特例化是模板的实例而不是重载。