Primer C++笔记记录(第十六章)
本书为Primer C++ 中文第五版
练习题笔记
(16.1)
当调用函数模板时,编译器通常用函数实参来为推断模板实参。
编译器用推断出的模板参数来实例化一个特定版本的函数。
当编译器实例化一个模板时,它使用实际的模板实参代替对应的模板参数来创建出模板的一个“实例”。
(16.2)
#include <functional>//less<>的头文件
template <typename T>
int compare(const T &v1, const T &v2) {
if(std::less<T>()(v1, v2)) return -1;
if(std::less<T>()(v2, v1)) return 1;
return 0;
}
(16.3)
/**** test3 ****/
class Sales_data {
friend bool operator<(const Sales_data&, const Sales_data&);
public:
Sales_data(const string& s, double p): isbn(s), price(p) { }
string isBn() const { return isbn; }
private:
string isbn;
double price;
};
bool operator<(const Sales_data& sd1, const Sales_data& sd2) {
return sd1.isBn() < sd2.isBn();
}
void test3() {
string s1("t1"), s2("t2");
Sales_data sd1(s1, 4.56), sd2(s2, 8.92);
print(compare(sd1, sd2));
print(compare(s1, s2));
}
/*
需要重载operator<,否则会出现如下错误
error: no match for ‘operator<’ (operand types are ‘const Sales_data’ and ‘const Sales_data’)
*/
(16.4)
/**** test4 ****/
template <typename I, typename V>
I findV(I beg, I end, V value) {
while(beg != end) {
if(*beg == value) break;
++beg;
}
return beg;
}
void test4() {
vector<int> v = {1, 2, 3, 4, 5};
auto f = findV(v.begin(), v.end(), 3);
cout << (f == v.end() ? "not found\n": "found\n");
list<string> l = {"a", "b", "c", "d", "e"};
auto fs = findV(l.begin(), l.end(), "sstr");
cout << (fs == l.end() ? "not found\n": "found\n");
}
(16.5)
/**** test5 ****/
template<typename I>
void printArr(I const& i) {
for(auto const& e : i) {
cout << e << " ";
}
cout << endl;
}
void test5() {
char c[] = {'a', 'b', 'c'};
int i[] = {1, 2, 3};
printArr(c);
printArr(i);
}
(16.6)
begin获取一个数组的引用,指向数组中的第一个元素
end获取数组的引用和大小,指向这个引用加上数组的大小
/**** test6 ****/
/**
*T(&arr)[s]
*参数声明一个名为arr的变量,该变量是对一个数组类型T的引用
*将数组传递给函数而不使其衰退为指针的方法
*可以在函数中使用数组,就像在声明它的作用域中使用数组样
*/
template<typename T, unsigned s>
T* beginOf(T(&arr)[s]) {
return arr;
}
template<typename T, unsigned s>
T* endOf(T(&arr)[s]) {
return arr+s;
}
void test6() {
string s[] = {"abc", "def", "ghi"};
cout << *(beginOf(s)) << endl;
cout << *(endOf(s) - 1) << endl;
}
(16.7)
/**** test7 ****/
template<typename T, unsigned s>
constexpr unsigned getSize(T(&arr)[s]) {
return s;
}
void test7() {
int i[] = {1, 2, 3};
cout << getSize(i) << endl;
}
(16.8)
因为大多数类通常会定义"!="而不是"<",使用"!="会减少错误
(16.9)
类模板:模板定义,可以从它实例化出特定的类。类模板的定义以关键字template开始,
后面跟尖括号对<>,其内为一个用逗号分隔的一个或多个模板参数的列表,随后是类的定义
函数模板:模板定义,可从它实例化出特定函数。函数模板的定义以关键字template开始,
后面跟尖括号对<>,其内为一个用逗号分隔的一个或多个模板参数的列表,随后是函数的定义
(16.10)
当一个类模板实例化时,编译器会使用模板实参来实例化出特定的类,它会重写类模板,
将模板参数的每个实例替换为给定的模板实参,每个实例都形成一个独立的类。
(16.11)
template <typename elemType> class ListItem;
template <typename elemType> class List {
List();
List(const List&);
List& operator=(const List&);
~List();
void insert(ListItem<elemType> *ptr, elemType value);
private:
ListItem<elemType> *front, *end;
};
(16.12)
#include <iostream>
#include <vector>
#include <string>
#include <memory>
using namespace std;
template <typename T> class BlobPtr;
template <typename T>
bool operator==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
template <typename T>
bool operator< (const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
template <typename T>
class Blob {
friend class BlobPtr<T>;
public:
typedef T value_type;
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)) { }
size_type size() const { return data->size(); }
void push_back(const T& t) { data->push_back(t); }
void push_back(T &&t) { data->push_back(move(t)); }
void pop_back() {
check(0, "pop_back on empty Blob");
data->pop_back();
}
T& back() {
check(0, "back on empty Blob");
return data->back();
}
const T& back() const {
check(0, "back on empty Blob");
return data->back();
}
T& operator[](size_type i) {
check(i, "subscript out of range");
return (*data)[i];
}
const T& operator[](size_type i) const {
check(i, "subscript out of range");
return (*data)[i];
}
private:
shared_ptr<vector<T>> data;
void check(size_type i, const string& msg) const;
};
template <typename T>
void Blob<T>::check(size_type i, const string& msg) const {
if(i >= data->size())
throw out_of_range(msg);
}
template <typename T>
class BlobPtr {
friend bool operator==<T>(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
friend bool operator< <T>(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs);
public:
BlobPtr(): curr(0) { }
BlobPtr(Blob<T>& a, size_t sz = 0): wptr(a.data), curr(sz) { }
T& operator*() const {
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
BlobPtr& operator++() {
check(curr, "increment past end of StrBlob");
++curr;
return *this;
}
BlobPtr& operator--() {
--curr;
check(curr, "decrement past begin of StrBlob");
return *this;
}
BlobPtr operator++(int) {
BlobPtr ret = *this;
++*this;
return ret;
}
BlobPtr operator--(int) {
BlobPtr ret = *this;
--*this;
return ret;
}
private:
shared_ptr<vector<T>> check(size_t, const string&) const;
weak_ptr<vector<T>> wptr;
size_t curr;
};
template <typename T>
bool operator==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs) {
if(lhs.wptr.lock() != rhs.wptr.lock()) {
throw runtime_error("ptrs to different Blobs!");
}
return lhs.curr == rhs.curr;
}
template <typename T>
bool operator<(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs) {
if(lhs.wptr.lock() != rhs.wptr.lock()) {
throw runtime_error("ptrs to different Blobs!");
}
return lhs.curr < rhs.curr;
}
template <typename T>
shared_ptr<vector<T>> BlobPtr<T>::check(size_t i, const string& msg) const {
auto ret = wptr.lock();
if(!ret)
throw runtime_error("undound BlobPtr");
if(i >= ret->size())
throw out_of_range(msg);
return ret;
}
int main() {
Blob<int> ia = {0,1,2,3,4};
cout << ia[2] << ia.back() << endl;
BlobPtr<int> bp(ia);
cout << *bp << endl;
cout << (bp == ++bp) << endl;
cout << *bp << endl;
bp--;bp--;
return 0;
}
(16.13)
添加了相等运算符和小于运算符
(16.14)
#include <iostream>
#include <string>
using namespace std;
template <unsigned H, unsigned W>
class Screen {
public:
typedef string::size_type pos;
Screen() = default;
Screen(char c): contents(H*W, c) { }
char get() const { return contents[cursor]; }
Screen &move(pos r, pos c) {
pos row = r * width;
cursor = row + c;
return *this;
}
void set(pos r, pos c, char a) {
contents[r*width + c] = a;
}
friend ostream& operator<<(ostream& os, const Screen<H, W>& c) {
unsigned int i, j;
for(i = 0; i < c.height; ++i) {
os << c.contents.substr(i*W, W) << endl;
}
return os;
}
friend istream& operator>>(istream& is, Screen<H, W>& c) {
char a;
is >> a;
string tmp(H*W, a);
c.contents = tmp;
return is;
}
private:
pos cursor = 0;
pos height = H, width = W;
string contents;
};
int main() {
Screen<10, 20> s;
cin >> s;
cout << s;
s.move(3, 5);
s.set(3, 5, 'z');
cout << s.get() << endl;
cout << s;
return 0;
}
(16.15)
添加了输入和输出友元函数
(16.16)
#include <iostream>
#include <string>
#include <memory>
using namespace std;
template <typename T>
class Vec {
public:
Vec() : elements(NULL),first_free(NULL), cap(NULL) { }
Vec(initializer_list<T> l) {
T* const newData = alloc.allocate(l.size());
T* p = newData;
for(const auto &t : l)
alloc.construct(p++, t);
elements = newData;
first_free = cap = elements+l.size();
}
Vec(const Vec&);
Vec &operator=(const Vec&);
~Vec();
void push_back(const T&);
void push_back(T &&s) {
chk_n_alloc();
alloc.construct(first_free++, move(s));
}
size_t size() const {return first_free - elements;}
size_t capacity() const {return cap - elements;}
T* begin() const {return elements;}
T* end() const {return first_free;}
//移动构造函数
Vec(Vec &&s) noexcept : elements(s.elements), first_free(s.first_free), cap(s.cap) {
s.elements = s.first_free = s.cap = NULL;
}
Vec& operator=(Vec &&s) noexcept {
if(this != &s) {
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = NULL;
}
return *this;
}
private:
static allocator<T> alloc;
void chk_n_alloc() {
if(size() == capacity()) reallocate();
}
pair<T*, T*> alloc_n_copy(const T*, const T*);
void free();
void reallocate();
T* elements; //数组首元素
T* first_free; //数组第一个空闲元素
T* cap; //数组尾后位置
};
template <typename T>
allocator<T> Vec<T>::alloc;
template <typename T>
void Vec<T>::push_back(const T &s) {
chk_n_alloc();
alloc.construct(first_free++, s);
}
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() {
if(elements) {
for(auto p = first_free; p != elements;) {
alloc.destroy(--p);
}
alloc.deallocate(elements, cap - elements);
}
}
template <typename T>
Vec<T>::Vec(const Vec &s) {
auto newdata = alloc_n_copy(s.begin(), s.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 &s) {
auto data = alloc_n_copy(s.begin(), s.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
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++,move(*elem++));
free();
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
int main() {
Vec<int> v = { 1, 2, 3, 4, 5 };
Vec<int> v2;
v2 = v;
std::cout << v2.capacity() << "\n";
v2.push_back(99);
for (auto t : v2)
std::cout << t << " ";
std::cout << v2.capacity() << "\n";
return 0;
}
(16.17)
在模板参数列表中,typename和class两个关键字的含义相同,都是表明模板参数是一个类型。
但是当我们希望通知编译器一个名字表示类型时,必须使用关键字typename,而不能使用class。
(16.18)
a>
模板参数列表每个参数都需要加上typename或class
template <typename T, typename U, typename V> void f1(T, U, V);
b>
函数内的形参名称和模板参数列表名称同名,不允许重声明模板参数
template <typename T> T f2(T&);
c>
函数在定义的时候才能指定为inline
template <typename T> T foo(T, unsigned int*);
d>
函数没有返回类型
template <typename T> void f4(T, T);
e>
合法,但是模板参数内部的Ctype是模板参数的类型,而非char
(16.19)
(16.20)
/***** test19And20 ****/
template<typename T>
void printCon19(T& t) {
for(typename T::size_type scan = 0; scan < t.size(); ++scan) {
cout << t[scan] << " ";
}
cout << endl;
}
template<typename T>
void printCon20(T& t) {
for(auto scan = t.begin(); scan < t.end(); ++scan) {
cout << *scan << " ";
}
cout << endl;
}
void test19And20() {
vector<int> vi = {1, 2, 3, 4};
deque<string> ds = {"hello", "world", "hahaha"};
printCon19(vi);
printCon19(ds);
printCon20(vi);
printCon20(ds);
}
(16.21)
#include <iostream>
#include <string>
using namespace std;
class DebugDelete {
public:
DebugDelete(ostream &s = cerr): os(s) { }
template <typename T> void operator()(T *p) const {
os << "deleting unique_ptr\n";
delete p;
}
private:
ostream& os;
};
int main() {
double* p = new double;
DebugDelete d;
d(p);
int* ip = new int;
DebugDelete()(ip);
return 0;
}
(16.22)
用法大致如下,就不再全部改写了。
unique_ptr<int, DebugDelete> p(new int, DebugDelete());
unique_ptr<string, DebugDelete> sp(new string, DebugDelete());
(16.23)
当shared_ptr计数减少到0的时候,会调用DebugDelete()函数删除指针
(16.24)
template <typename T, typename It>
Blob<T>::Blob(It b, It e): data(make_shared<vector<T>>(b, e)) { }
(16.25)
extern template class vector<string>
实例化声明,当编译器遇到extern模板声明时,它不会在本文件中生成实例化代码。
并且表示承诺在程序的其他位置有该实例化的一个非extern声明(定义)
template class vector<Sales_data>
用Sales_data实例化vector
(16.26)
不可以;因为在一个类模板的实例化定义中,所用的类型必须能用于模板的所有成员函数。
(16.27)
a>
char 实例化模板
b>
double 实例化模板
c>
int 实例化模板
d>
存在该实例的定义,不需要再次实例化
e>
存在该实例的定义,不需要再次实例化
f>
string 实例化模板
(16.28)
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class DebugDelete {
public:
DebugDelete(ostream &s = cerr): os(s) { }
template <typename T> void operator()(T *p) const {
os << "deleting unique_ptr: " << *p << "\n";
delete p;
}
private:
ostream& os;
};
template <typename T>
class shared_ptr_tmp {
public:
shared_ptr_tmp(): spt(nullptr), use_count(new size_t(1)), deleter(DebugDelete()) { }
shared_ptr_tmp(T* tmp): spt(tmp), use_count(new size_t(1)), deleter(nullptr) { }
shared_ptr_tmp(T* tmp, function<void(T*)> d) {
spt = tmp;
deleter = d;
use_count = new size_t(1);
}
//copy
shared_ptr_tmp(const shared_ptr_tmp& tmp): spt(tmp.spt), use_count(tmp.use_count), deleter(tmp.deleter) {
++*use_count;
}
//Copy assignment
shared_ptr_tmp& operator=(const shared_ptr_tmp& tmp) {
++*(tmp.use_count);
~shared_ptr_tmp();
spt = tmp.spt;
use_count = tmp.use_count;
deleter = tmp.deleter;
}
T& operator*() { return *spt; }
void reset(T *pointer, std::function<void(T*)> d) {
if (spt != pointer) {
~shared_ptr_tmp();
spt = pointer;
use_count = new size_t(1);
}
deleter = d;
}
~shared_ptr_tmp() {
if(--*use_count == 0 && spt) {
deleter? deleter(spt) : delete spt;
delete use_count;
}else if(!spt){
delete use_count;
}
use_count = nullptr;
spt = nullptr;
}
private:
T* spt;
function<void(T*)> deleter;
size_t* use_count;
};
template <typename T, typename D>
class unique_ptr_tmp {
public:
unique_ptr_tmp() = default;
unique_ptr_tmp(T* up): upt(up) { }
T& operator*() const { return *upt; }
T* get() const noexcept { return upt; }
void reset(T* p) noexcept { deleter(upt); upt = p;}
~unique_ptr_tmp()
{
deleter(upt);
}
private:
T* upt = nullptr;
D deleter = D();
};
int main() {
shared_ptr_tmp<int> i(new int(42));
cout << *i << endl;
shared_ptr_tmp<string> s(new string("hello"), DebugDelete());
cout << *s << endl;
unique_ptr_tmp<int, DebugDelete> ui(new int(33));
return 0;
}
(16.29)
略
(16.30)
略
(16.31)
略
(16.32)
编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配
(16.33)
const转换:可以将一个非const对象的引用(或指针)传递给一个const的引用(或指针)形参
数组或函数指针转换:如果函数形参不是引用类型,则可以对数组或函数类型的实参应用正常的指针转换;
一个数组实参可以转换成一个指向其首元素的指针;一个函数实参可以转换成一个该函数类型的指针;
(16.34)
乍一看,以为是一样的。但实则不同
a> char[3] 和 char[6], 不合法,会报错
b> char[4] 和 char[4], T的类型为char*
(16.35)
a> 合法,T的类型为char
b> 合法,T的类型为double,因为float可以转换成int
c> 合法,T的类型为char
d> 不合法
(16.36)
a> T的类型为int*
b> T1和T2的类型都为int*
c> T的类型为const int*
d> T1和T2的类型都为const int*
e> 不合法,类型不一致
f> T1类型为int*,T2类型为const int*
(16.37)
void test37() {
int a = 2;
double b = 2.3;
cout << max<double>(a, b) << endl;
}
(16.38)
make_share如果不提供显示模板实参,则无法给参数分配适当的内存
(16.39)
void test39() {
cout << compare<string>("abc", "aaaaaa") << endl;
}
(16.40)
函数合法,但是对于传递的实参类型有限制,实参类型必须支持operator+(int)操作。
/**** test 40 ****/
template <typename It>
auto fcn3(It beg, It end) -> decltype(*beg + 0) {
return *beg;
}
void test40() {
vector<int> vi = {0, 1, 2, 3};
auto target = fcn3(vi.begin(), vi.end());
cout << target << endl;
//非法
/*
vector<string> vs = {"z", "l", "f"};
auto tar = fcn3(vs.begin(), vs.end());
cout << tar << endl;
*/
vector<char> vc = {'z', 'l', 'f'};
auto tarc = fcn3(vc.begin(), vc.end());
cout << tarc << endl;
}
(16.41)
/**** test 41 ****/
template <typename TL, typename TR>
auto sum(TL l, TR r) -> decltype(l + r) {
return l + r;
}
void test41() {
cout << sum(12345678987654321, 12345678987654321) << endl;
}
(16.42)
a> T的类型为int&, val则是int& &&折叠成int&
b> T的类型为const int&, val则是const int& &&折叠成const int&
c> T的类型为int, val则是int&&
(16.43)
因为 i = ci 是一个赋值语句,返回一个左值。所以和上面的a一样,T是int&, val是int&
(16.44)
为T时:
a>T: int
b>T: int, const会被忽略
c>T: int, i*ci返回一个右值将会被复制给T
为const T&时:
a>T: int
b>T: int
c>T: int
(16.45)
对于42,是一个右值,所以T的类型是int&&,而val类型是int&& &&将会被折叠为int&&,所以vector<int&&>合法。
对于int,是一个左值。所以T的类型是int&,而val类型是int& &&将被折叠为int&,所以vector<int&>非法。
(16.46)
在每次迭代中,解引用操作符*返回一个左值,然后这个左值通过move操作变成右值;
因为成员函数构造函数使用右值引用而不是左值引用。
(16.47)
/**** test 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));
}
void g(int&& i, int& j) {
cout << i++ << " " << j++ << endl;
}
void test47() {
int i = 1, j = 2;
flip(g, j, 1);
cout << i << " " << j << endl;
}
(16.48)
/**** test 48 ****/
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();
}
void test48() {
string s("hi");
cout << debug_rep(s) << endl;
cout << debug_rep(&s) << endl;
}
(16.49)
g(T t)
g(T *t)
g(T t)
g(T *t)
*****
f(T t)
f(T t)
f(T t)
f(const T *t)
(16.50)
/**** test 49&50 ****/
template <typename T> void f(T t) {
cout << "f(T t)" << endl;
}
template <typename T> void f(const T *t) {
cout << "f(const T *t)" << endl;
}
template <typename T> void g(T t) {
cout << "g(T t)" << endl;
}
template <typename T> void g(T *t) {
cout << "g(T *t)" << endl;
}
void test49() {
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42);g(p);g(ci);g(p2);
cout << "*****" << endl;
f(42);f(p);f(ci);f(p2);
}
(16.51)
3 3
2 2
1 1
0 0
(16.52)
/**** test 51&52 ****/
template<typename T, typename... Args>
void foo(const T &t, const Args& ... args) {
cout << sizeof...(Args) << " " << sizeof...(args) << endl;
}
void test51() {
int i = 0;
double d = 3.14;
string s = "how now brown cow";
foo(i, s, 42, d);
foo(s, 42, "hi");
foo(d, s);
foo("hi");
}
(16.53)
/**** test 53&54&55 ****/
template <typename T> ostream &printt(ostream &os, const T &t) {
return os << t << "\n";
}
template <typename T, typename... Args>
ostream &printt(ostream &os, const T &t, const Args&... args) {
os << t << ", ";
return printt(os, args...);
}
void test53() {
int i = 0;
double d = 3.14;
string s = "how now brown cow";
const char* c = "hello";
cout << "1:\n";
printt(cout, i);
cout << "2:\n";
printt(cout, i, d);
cout << "5:\n";
printt(cout, i, d, s, c);
}
(16.54)
编译失败
(16.55)
编译报错,error: no matching function for call to ‘printt(std::ostream&)’
(16.56)
/**** test 56 ****/
template <typename T> string debug_repp(const T &t) {
ostringstream ret;
ret << t;
return ret.str();
}
template <typename... Args>
ostream &errorMsg(ostream &os, const Args&... args) {
return printt(os, debug_repp(args)...);
}
void test56() {
errorMsg(cerr, "other", 1, 3.15);
}
(16.57)
可变参数版本的errorMsg参数不仅可以有不同的参数个数,也可以有不同的参数类型。
(16.58)
template<typename... Args> void emplace_back(Args... args) {
chk_n_alloc();
alloc.construct(first_free++, forward<Args>(args)...);
}
(16.59)
construct调用中的扩展为forward<string>(s),将得到一个左值参数,然后将这个参数传递给string的构造函数创建新元素。
(16.60)
make_shared应该是一个可变参数模板函数,它将所有的参数转发给底层构造函数,
这些构造函数在动态内存中分配和初始化一个对象。然后通过包装原始指针构建一个shared_ptr。
(16.61)
/**** test 61 ****/
template <typename T, typename... Args>
auto make_share(Args&&... args) -> shared_ptr<T> {
return shared_ptr<T>(new T(forward<Args>(args)...));
}
void test61() {
auto n = make_share<int>(42);
cout << *n << endl;
auto s = make_share<string>(10, 'c');
cout << *s << endl;
}
(16.62)
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 {
return hash<string>()(s.bookNo) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue);
}
};
}
unordered_multiset<Sales_data> SDset;
SDset.emplace("TLBB", 5, 6.66);
(16.63)
(16.64)
/**** test 63&64 ****/
template <typename T> size_t count(vector<T> const& v, T value) {
size_t counts = 0;
for(auto t : v)
if(t == value) ++counts;
return counts;
}
template <> size_t count(vector<const char*> const& v, const char* value) {
size_t counts = 0;
for(auto t : v)
if(t == value) ++counts;
return counts;
}
void test63() {
vector<int> vi = {0, 1, 2, 2, 2, 3, 4};
vector<double> vd = {0.1, 0.2, 0.2, 0.3};
vector<string> vs = {"a", "ab", "ab", "abc"};
string s = "ab";
cout << count(vi, 2) << " " << count(vd, 0.2) << " " << count(vs, s) << endl;
vector<const char*> vcc = {"a", "ab", "ab", "abc"};
cout << count(vcc, "ab") << endl;
}
(16.65)
/**** test 65 ****/
template<>
string debug_rep(const char* s) {
ostringstream ret;
cout << "<>const char*: \n";
ret << s;
return ret.str();
}
template<>
string debug_rep(char* s) {
ostringstream ret;
cout <<"<>char*: \n";
ret << s;
return ret.str();
}
void test65() {
char p[] = "abcd";
cout << debug_rep(p) << endl;
const char* pp = "zxcv";
cout << debug_rep(pp) << endl;
}
(16.66)
重载会改变函数匹配,但是特例化并不会
(16.67)
不影响,定义函数模板的特例化版本时,本质上是接管了编译器的工作。
所以特例化版本本质是是一个实例,而不是函数名的一个重载版本,不影响函数匹配。