16.1
根据模板参数的类型实例化出一个该类型的函数
16.2
#include <iostream>
#include <string>
#include <functional> //less
//#include "../../7.21/7.21/标头.h"
template<typename T>
int compare(const T &a, const T &b) {
if (std::less<T>()(a, b))return 1;
if (std::less<T>()(b, a))return -1;
return 0;
}
int main()
{
using namespace std;
string a, b;
//Sales_data b1("a"), b2("b");
cin >> a >> b;
if (compare(a, b) > 0)cout << a << "<" << b << endl;
if (compare(a, b) < 0)cout << a << ">" << b << endl;
if (!compare(a, b))cout << a << "=" << b << endl;
//cout << compare(b1, b2);
system("pause");
return 0;
}
16.3
错误:Sales_data类型未定义运算符"<"
16.4
#include <iostream>
#include <vector>
#include <list>
#include <string>
template<typename Iterator, typename Value>
auto find(Iterator first, Iterator last, Value const& value)
{
for (; first != last && *first != value; ++first);
return first;
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto is_in_vector = v.cend() != ::find(v.cbegin(), v.cend(), 8);
std::cout << (is_in_vector ? "找到\n": "没找到\n");
std::list<std::string> l = { "aa", "bb", "cc", "dd", "ee", "ff", "gg" };
auto is_in_list = l.cend() != ::find(l.cbegin(), l.cend(), "ab");
std::cout << (is_in_list ? "找到\n" : "没找到\n");
system("pause");
return 0;
}
16.5
#include <iostream>
//template<typename T>
//void prin(const T &a)
//{
// auto b = std::begin(a), e = std::end(a);
// for (; b != e; ++b)
// std::cout << *b << " ";
//}
//int main()
//{
// using namespace std;
// int a[] = { 1,2,3,4,5,6,9,8,7 };
// string str = "primer 5";
// prin(a);
// prin(str);
// system("pause");
// return 0;
//}
template<class T, unsigned N>
void prin(T(&ar)[N])
{
for (int i = 0; i < N; ++i)
std::cout << ar[i];
}
int main()
{
using namespace std;
int ar[9] = { 4,0,8,6,8,6,4,7,7 };
char str[] = "helloworld!";
prin(ar);
prin(str);
prin("c++ primer");
system("pause");
return 0;
}
16.6
#include <iostream>
template<typename T>
void print(const T &ar) {
auto beg = ::begin(ar), end = ::end(ar);
while (beg != end) {
std::cout << *beg++ << " ";
}
}
template<class T>
auto begin(const T &ar)
{
return ar;
}
template<class T>
auto end(const T &ar)
{
return ar + (sizeof ar) / sizeof(*ar); //整个数组的大小除以单个元素的大小得到数量,指向数组之后
}
int main()
{
using namespace std;
int l[] = { 2,0,1,6,0,1,0,6 };
print("c++ primer");
print(l);
system("pause");
return 0;
}
16.7
#include <iostream>
template<class T>
constexpr size_t sizear(const T &ar) {
return sizeof ar;
}
int main()
{
int ar[] = { 1,2,3,4,5,6,7,8 };
int *p = ar;
std::cout << sizear(ar) << std::endl;
system("pause");
return 0;
}
16.8
因为所有的标准库容器都有提供==与!=的运算符,而不一定有提供<运算符,所以使用!=能在所有的标准库容器上工作
16.9
函数模板就是一个公式,可以用来生成特定类型的函数版本。
16.10
生成一个特定类型的类,该类中特定类型被替换
16.11
//Blob.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
#include <memory> //shared_ptr
template<typename T> class Blob;
template<typename T> class BlobPtr;
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class Blob
{
public:
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob &l, const Blob &r);
typedef T value_type;
typedef typename std::vector<T>::size_type size_type; //把size_type视为类型名,忽略vector里同名的(如果有)静态变量
Blob();
Blob(std::initializer_list<T> il);
size_type size()const { //返回元素数量
return data->size();
}
bool empty()const { //是否为空
return data->empty();
}
void push_back(const T &t) { //添加元素到末尾
data->push_back(t);
}
void push_back(T &&t) {
data->push_back(std::move(t));
}
void pop_back(); //弹出末尾元素
T &back(); //返回末尾元素的引用
T &operator[](size_type i); //返回第i个元素的引用
private:
std::shared_ptr<std::vector<T>> data;
void check(size_type i, const std::string &msg)const;
};
template<typename T>
void Blob<T>::check(size_type i, const std::string &msg)const {
if (i >= data->size())
throw std::out_of_range(msg);
}
template<typename T>
T &Blob<T>::back() {
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
T &Blob<T>::operator[](size_type i) {
check(i, "subscript out range");
return (*data)[i];
}
template<typename T>
void Blob<T>::pop_back() {
check(0, "pop_back on empty Blob");
data->pop_back();
}
template<typename T>
Blob<T>::Blob():data(std::make_shared<std::vector<T>>()){
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>> (il)) {
}
template<typename T>
bool operator==(const Blob<T> &l, const Blob<T> &r) {
if (l.data != r.data)
return false;
return true;
}
//BlobPtr.h
#pragma once
#include "Blob.h"
template<typename T>
class BlobPtr {
public:
BlobPtr();
BlobPtr(Blob<T> &a, size_t sz = 0);
T &operator*()const;
BlobPtr &operator++();
BlobPtr &operator--();
private:
std::shared_ptr<std::vector<T>> check(std::size_t i, const std::string &s)const;
std::weak_ptr<std::vector<T>> wptr;
std::size_t curr;
};
template<typename T>
BlobPtr<T>::BlobPtr() :curr(0) {}
template<typename T>
BlobPtr<T>::BlobPtr(Blob<T> &a, size_t sz /* = 0 */) : wptr(a.data), curr(sz) {}
template<typename T>
T &BlobPtr<T>::operator*()const {
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
template<typename T>
BlobPtr<T> &BlobPtr<T>::operator++() {
++curr;
check(curr, "++obj error");
return *this;
}
template<typename T>
BlobPtr<T> &BlobPtr<T>::operator--() {
--curr;
if (curr < 0)
throw std::out_of_range("--obj error");
return *this;
}
template<typename T>
std::shared_ptr<std::vector<T>> BlobPtr<T>::check(std::size_t i, const std::string &s)const {
auto ret = wptr.lock(); //确认未被释放内存
if (!ret)
throw std::out_of_range("unbound BlobPtr");
if (i >= ret->size())
throw std::out_of_range(s);
return ret;
}
16.13
1 VS 1
让不同类型的类模板相等无意义
16.14,16.15
#pragma once
#include <string>
#include <iostream>
struct xyc {
int x=0;
int y=0;
char c=' ';
};
template<unsigned N,unsigned M>
class Screen
{
unsigned cursor = 0;
unsigned width = N, height = M;
std::string contents;
public:
Screen() = default;
Screen(char c) :contents(N*M, c) {}
char get()const { return contents[cursor]; }
Screen set(xyc c) {
cursor = --c.x*width + --c.y;
contents[cursor] = c.c;
return *this;
}
template<unsigned NN,unsigned MM>
friend std::ostream &operator<<(std::ostream &os, const Screen<NN, MM> &s);
template<unsigned NN, unsigned MM>
friend std::istream &operator>>(std::istream &is, Screen<NN, MM> &s);
};
template<unsigned NN, unsigned MM>
std::ostream &operator<<(std::ostream &os, const Screen<NN, MM> &s)
{
for (unsigned i = 0; i < s.width; ++i)
{
for (unsigned j = 0; j < s.height; ++j)
putchar(s.contents[i*s.width + j]);
putchar('\n');
}
return os;
}
template<unsigned NN, unsigned MM>
std::istream &operator>>(std::istream &is, Screen<NN, MM> &s)
{
xyc c;
is >> c;
s.set(c);
return is;
}
#include "标头.h"
std::istream &operator>>(std::istream &is, xyc &c) {
is >> c.x;
is >> c.y;
is >> c.c;
return is;
}
int main()
{
using namespace std;
Screen<6, 6> scr('-');
cout << scr;
cin >> scr;
cout << scr;
system("pause");
return 0;
}
16.16
#pragma once
#include <iostream>
#include <string>
#include <memory> //allocator
#include <utility> //move
#include <initializer_list>
#include <algorithm> //for_each
template<class T>
class StrVec
{
std::allocator<T> alloc;//为所有StrVec对象分配内存用
void chk_n_alloc() //如果剩余空间为0就分配新空间
{
if (size() == capacity())
reallocate();
}
std::pair<T *, T *> alloc_n_copy(const T *b, const T *e);//创建一个内容为b到e之间的元素的对象,并返回这个对象的一对头尾指针
void free();//释放所有alloc分配的所有内存
void reallocate();//移动当前对象的元素到2倍对象大小的新对象里
T *elements;
T *first_free;
T *cap;
public:
StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(std::initializer_list<T> il);
StrVec(const StrVec &s);
StrVec(StrVec &&s);
StrVec &operator=(StrVec &&s);
StrVec &operator=(const StrVec &s);
bool operator==(const StrVec &s)//14.16
{
if (size() != s.size())
return false;
auto it = elements, its = s.elements;
while (it != first_free)
{
if (*it++ != *its++)
return false;
}
return true;
}
bool operator!=(const StrVec &s)//14.16
{
return !(*this == s);
}
bool operator<(const StrVec &s)//14.18
{
if (size()>s.size())
return false;
else if (size() < s.size)
return true;
for (auto it = elements, its = s.elements; it != first_free; ++it, ++its)
{
if (*it == *its)
continue;
else if (*it > *its)
return false;
else
return true;
}
return false;
}
bool operator>(const StrVec &s)//14.18
{
return !(*this < s) && *this != s;
}
bool operator<=(const StrVec &s)//14.18
{
return !(*this > s);
}
bool operator>=(const StrVec &s)//14.18
{
return !(*this < s);
}
StrVec &operator=(std::initializer_list<T> il)
{
auto nobj = alloc_n_copy(il.begin(), il.end());
free();
elements = nobj.first;
first_free = cap = nobj.second;
return *this;
}
T &operator[](std::size_t n)
{
return elements[n];
}
const T &operator[](std::size_t n)const
{
return elements[n];
}
~StrVec();
void push_back(const T &s);//把T添加到尾后指针
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;
}
template<class TT>
friend std::ostream &operator<<(std::ostream &os, const StrVec<TT> &s);
};
template<class T>
void StrVec<T>::push_back(const T &s)
{
chk_n_alloc();//确保空间剩余
alloc.construct(first_free++, s);//在尾后构建一个s(s的拷贝构造函数构造),并把尾后指针first_free指向下一个
}
template<class T>
std::pair<T *, T *> StrVec<T>::alloc_n_copy(const T *b, const T *e)
{
auto data = alloc.allocate(e - b);//分配并返回n个T对象的地址 T *
return{ data, std::uninitialized_copy(b, e, data) };//uninit_copy返回尾后指针T *
//把l~r之间的元素拷贝到data开始的地址,并返回data尾后,然后使用data(begin)和返回值(end)构建一个pair<T *,T *>
}
template<class T>
void StrVec<T>::free()
{
if (elements)//如果不为空
{
for (auto p = first_free; p != elements;)
alloc.destroy(--p);//从最后一个元素开始向前摧毁,调用p的析构函数
//for_each(elements, first_free, [this](T *s){alloc.destroy(s); });//13.43
alloc.deallocate(elements, cap - first_free);//释放elements开始的n的T对象的内存
}
}
template<class T>
StrVec<T>::StrVec(std::initializer_list<T> il)
{
auto newdata = alloc_n_copy(il.begin(), il.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
template<class T>
StrVec<T>::StrVec(const StrVec &s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());//创建一个s的副本 值
elements = newdata.first;//把头指向新创建的副本的头
first_free = cap = newdata.second;//把尾后和内存尾指向副本的尾(以后调用会调用chk_n_alloc,不用担心剩余空间大小)
}
template<class T>
StrVec<T>::StrVec(StrVec &&s) :elements(s.elements), first_free(s.first_free), cap(s.cap)
{
s.elements = s.first_free = s.cap = nullptr;
}
template<class T>
StrVec<T> &StrVec<T>::operator=(StrVec &&s)
{
if (this == &s)
return *this;
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = nullptr;
return *this;
}
template<class T>
StrVec<T>::~StrVec()
{
free();//清理当前对象alloc分配的内存
}
template<class T>
StrVec<T> &StrVec<T>::operator=(const StrVec &s)
{
if (this == &s)
return *this;
auto data = alloc_n_copy(s.elements, s.first_free);
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
template<class T>
void StrVec<T>::reallocate()
{
auto newcapacity = size() ? 2 * size() : 1; //当前空间的两倍大小
auto newdata = alloc.allocate(newcapacity); //分配并返回newcapacity个T对象大小的空间
auto dest = newdata;
auto elem = elements;//指向当前对象的头
for (size_t i = 0; i != size(); ++i)
{
alloc.construct(dest++, std::move(*elem++));//move会让elem指向的T对象放弃自己的内存管理权并返回,然后construct使用T的移动构造函数构建dest指向的地址
} //接受dest会指向newdata的尾后
free(); //移动完后释放当前对象指向的内存
elements = newdata; //指向新头
first_free = dest; //指向新尾后
cap = elements + newcapacity; //指向内存尾
}
template<class TT>
std::ostream &operator<<(std::ostream &os, const StrVec<TT> &s)
{
for (auto x : s)
std::cout << x;
return os;
}
#include "标头.h"
int main()
{
using namespace std;
StrVec<char> str{ 'c','l','a','n','n','a','d' };
cout << str;
system("pause");
return 0;
}
16.17
template<class T,typename T>在声明模板时没有区别,但是在制定为类型而不是静态值时就必须用typename: typename T::size_type func(); 这里的size_type是类型而不是值。
16.18
1、错误,不能连续声明模板参数 改为: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 f4(T,T);
e、错误,模板参数将覆盖外层的Ctype 改为:typedef char C;或者是template<typename C> C f5(C a);
16.19
#pragma once
#include <iostream>
template<typename T>
void prin(T &s, std::ostream &os)
{
typename T::size_type n=0,size = s.size();
auto iter = s.begin();
for (; n < size; ++n)
{
os << *iter++;
}
}
#include "标头.h"
#include <vector>
int main()
{
using namespace std;
vector<char> str = { '1','2','3','4','5','6','7','8','9','0' };
prin(str, cout);
system("pause");
return 0;
}
16.20
#pragma once
#include <iostream>
template<typename T>
void prin(T &s, std::ostream &os)
{
for (auto beg = s.begin(); beg != s.end(); ++beg)
{
os << *beg;
}
}
#include "标头.h"
#include <vector>
#include <list>
int main()
{
using namespace std;
vector<char> str = { '1','2','3','4','5','6','7','8','9','0' };
list<int> lint = { 1,2,3,4,5,6,7,8,9 };
prin(str, cout);
prin(lint,cout);
system("pause");
return 0;
}
16.21
#pragma once
#include <iostream>
class DebugDelete
{
std::ostream &os;
public:
DebugDelete(std::ostream &s = std::cerr) :os(s) {}
template<class T>
void operator()(T *p) {
os << "delete obj!!!" << std::endl;
delete p;
}
};
16.22
#ifndef HEAD_H_
#define HEAD_H_
#include "DebugDelete.h"
#include <iostream>
#include <fstream> //ifstream
#include <string>
#include <vector>
#include <sstream> //istringstream
#include <map>
#include <set>
#include <memory> //shared_ptr
class QueryResult;
using line_no = std::vector < std::string > ::size_type;
class TextQuery
{
std::shared_ptr<std::vector<std::string>> file; //保存整个文件内容,按行分
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm; //每个单词对应行号
public:
TextQuery(std::ifstream &is);
QueryResult query(const std::string &s)const; //返回QR,单词、行号set,还有关联到文件内容
};
class QueryResult
{
friend std::ostream &print(std::ostream &os, const QueryResult &qr);
std::string sought;
std::shared_ptr<std::set<line_no>> lines; //记录出现的行号
std::shared_ptr<std::vector<std::string>> file; //关联到文件内容
public:
QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f) :sought(s), lines(p), file(f){}
};
TextQuery::TextQuery(std::ifstream &is) :file(new std::vector<std::string>(),DebugDelete(std::cout)) //为智能指针file分配空间 16.22
{
std::string text;
while (getline(is, text))
{
file->push_back(text);
int n = file->size() - 1;
std::istringstream line(text);
std::string word;
while (line >> word)
{
auto &lines = wm[word]; //如果word在wm中第一次出现,那么对应的set就未分配内存,所以为空
if (!lines) //如果第一次出现
lines.reset(new std::set<line_no>());
lines->insert(n);
}
}
}
QueryResult TextQuery::query(const std::string &s)const
{
static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>()); //当没找到单词时返回 内存常驻
auto loc = wm.find(s);
if (loc == wm.end())
return QueryResult(s, nodata, file);
else
return QueryResult(s, loc->second, file);
}
std::ostream &print(std::ostream &os, const QueryResult &qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " " << (qr.lines->size() > 1 ? "times" : "time") << std::endl;
for (auto x : *qr.lines) //*(qr.file->begin()+x)
os << "\t(line " << x + 1 << ") " << (*qr.file)[x] << std::endl; //file返回一个指向vec的智能指针,解引用后得到vector 然后使用下标运算符
return os;
}
#endif
16.23
在对象介绍声明周期时掉用
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
#include <memory> //shared_ptr
template<typename T> class Blob;
template<typename T> class BlobPtr;
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class Blob
{
public:
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob &l, const Blob &r);
typedef T value_type;
typedef typename std::vector<T>::size_type size_type; //把size_type视为类型名,忽略vector里同名的(如果有)静态变量
Blob();
Blob(std::initializer_list<T> il);
template<class U>
Blob(U b, U e);
size_type size()const { //返回元素数量
return data->size();
}
bool empty()const { //是否为空
return data->empty();
}
void push_back(const T &t) { //添加元素到末尾
data->push_back(t);
}
void push_back(T &&t) {
data->push_back(std::move(t));
}
void pop_back(); //弹出末尾元素
T &back(); //返回末尾元素的引用
T &operator[](size_type i); //返回第i个元素的引用
private:
std::shared_ptr<std::vector<T>> data;
void check(size_type i, const std::string &msg)const;
};
template<typename T>
void Blob<T>::check(size_type i, const std::string &msg)const {
if (i >= data->size())
throw std::out_of_range(msg);
}
template<typename T>
T &Blob<T>::back() {
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
T &Blob<T>::operator[](size_type i) {
check(i, "subscript out range");
return (*data)[i];
}
template<typename T>
void Blob<T>::pop_back() {
check(0, "pop_back on empty Blob");
data->pop_back();
}
template<typename T>
Blob<T>::Blob():data(std::make_shared<std::vector<T>>()){
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {
}
template<typename T>
bool operator==(const Blob<T> &l, const Blob<T> &r) {
if (l.data != r.data)
return false;
return true;
}
template<class T>
template<class U>
Blob<T>::Blob(U b, U e) :data(std::make_shared < std::vector<T>>(b, e)) {}
#include "Blob.h"
int main()
{
using namespace std;
int vi[] = { 1,2,3,4,5,6 };
Blob<int> b(begin(vi), end(vi));
for (typename Blob<int>::size_type i = 0; i != b.size(); ++i)
{
cout << b[i];
}
system("pause");
return 0;
}
16.25
extern template class vector<string>;//声明一个实例化,但是该实例化的定义不一定在本模块,提示编译器可以在其他模块查找
template clss vector<Sales_data>;//定义一个实例化,让编译器生成一个实例
16.26
不可以,因为下面的就会报错:
vector<NoDefault> vN(10);//error,没有NoDefault类没有默认构造函数
16.27
a:没有实例化,只有在有数据时才会实例化
b:没有实例化,引用并不会实例化,因为没有数值存在
c:实例化出一个Stack<int>的实例
d:没有实例化,指针不会实例化,他包含的是地址
e:实例化出一个Stack<char>的实例,因为函数接收到数据,而且是按值传递
f:实例化出一个Stack<string>的实例,
16.28
//DebugDelete.h
#pragma once
#include <iostream>
class DebugDelete
{
public:
DebugDelete(std::ostream& s = std::cerr) : os(s) { }
template<typename T>
void operator() (T* p) const
{
os << "deleting ptr" << std::endl;
delete p;
}
private:
std::ostream& os;
};
#pragma once //shared_p.h
#include <functional>
#include "DebugDelete.h"
#include <memory>
template<typename T>class shared_p;
class SharedPtrControlBlock //保存引用数所使用
{
template<typename T>friend class shared_p;
int _count;
SharedPtrControlBlock() :_count(1){}
};
template<typename T>
class shared_p
{
T *_ptr;
SharedPtrControlBlock *control_block;
std::function<void(T*)> deleter{ DebugDelete() };
template<typename U>
void Initialize(const shared_p<U> &r)
{
if (r.control_block != nullptr)
{
AtomicIncrement(&r.control_block->_count);
_ptr = r._ptr;
control_block = r.control_block;
deleter = r.deleter;
}
}
public:
explicit shared_p(T *ptr = nullptr, std::function<void(T*)> f = DebugDelete())
:_ptr(ptr),
control_block(_ptr != nullptr ? new SharedPtrControlBlock : nullptr),
deleter(f) {}
shared_p(const shared_p &p)
{
Initialize(p);
}
shared_p &operator=(shared_p &p)
{
if (_ptr != p._ptr)
{
shared_p temp(p);
swap(temp);
}
return *this;
}
shared_p(std::shared_ptr<T> &&sp)
{
if (sp.unique())
{
/*shared_p<T> temp =shared_p(new T(*sp));
_ptr = temp._ptr;
control_block = temp.control_block;*/
*this = shared_p(new T(*sp));
}
else
throw std::runtime_error("unique error!!");
}
template<typename U>
friend std::ostream &operator<<(std::ostream &os, const shared_p<U> &s);
~shared_p()
{
if (_ptr != nullptr)
{
if (AtomicDecrement(&control_block->_count) == 0)
{
deleter(_ptr);
delete control_block;
}
}
}
int AtomicDecrement(int *count)
{
return --*count;
}
int AtomicIncrement(int *count)
{
return ++*count;
}
void reset(T *p = nullptr,std::function<void(T*)> del=DebugDelete())
{
if (p != _ptr)
{
shared_p temp(p);
temp->swap(*this);
deleter = del;
}
}
void swap(shared_p &r)
{
std::swap(_ptr, r._ptr);
std::swap(control_block, r.control_block);
std::swap(deleter, r.deleter);
}
T *get()const
{
return _ptr;
}
T &operator*()const
{
return *_ptr;
}
auto &operator[](int n)
{
return (*_ptr)[n];
}
T *operator->()const
{
return _ptr;
}
int use_count()const //返回引用数
{
return control_block ? control_block->_count : 1;
}
bool unique()const //是否单一占用 引用==1
{
return use_count() == 1;
}
};
template<class T>
std::ostream &operator<<(std::ostream &os, const shared_p<T> &s)
{
os << *s._ptr;
return os;
}
#pragma once //unique_p.h
#include <functional>
#include "DebugDelete.h"
template<typename T>
class unique_p
{
T *_ptr;
std::function<void(T*)> deleter{ DebugDelete() };
public:
explicit unique_p(T *ptr = nullptr, std::function<void(T*)> del = DebugDelete()) :_ptr(ptr), deleter(del) {}
unique_p(unique_p &u) :_ptr(u._ptr), deleter(u.deleter)
{
u._ptr = nullptr;
u.deleter = nullptr;
}
unique_p(unique_p &&u) :_ptr(u._ptr), deleter(u.deleter)
{
u._ptr = nullptr;
u.deleter = nullptr;
}
unique_p &operator=(unique_p &u)
{
_ptr = (u._ptr);
deleter = u.deleter;
u.deleter = nullptr;
u._ptr = nullptr;
}
unique_p &operator=(unique_p &&u)
{
_ptr = (u._ptr);
deleter = u.deleter;
u.deleter = nullptr;
u._ptr = nullptr;
}
template<typename U>
friend std::ostream &operator<<(std::ostream &os, const unique_p &u);
~unique_p()
{
delete _ptr;
}
void swap(unique_p &u)
{
std::swap(_ptr, u._ptr);
std::swap(deleter, u.deleter);
}
void reset(T *p = nullptr, std::function<void(T*)> del = DebugDelete())
{
if (p != _ptr)
{
unique_p<T> temp(p);
temp.swap(*this);
}
}
T *get()const
{
return _ptr;
}
T &operator*()const
{
return *_ptr;
}
auto &operator[](int n)
{
return (*_ptr)[n];
}
T *operator->()const
{
return _ptr;
}
};
template<typename T>
std::ostream &operator<<(std::ostream &os, const unique_p<T> &u)
{
os << *_ptr;
return os;
}
#include <iostream>
#include "shared_p.h"
#include "unique_p.h"
#include <vector>
#include <string>
#include <memory>
int main()
{
using namespace std;
shared_p<vector<char>> sv(new vector<char>);
char a;
while ((a = getchar()) != 'q')
sv->push_back(a);
for (auto &x : *sv)
cout << x;
unique_p<int> ui(new int(4096));
cout << *ui;
unique_p<int> uii(ui);
cout << *uii;
system("pause");
cout << *ui; //出错,空指针
system("pause");
return 0;
}
16.29、16.30
#pragma once //shared_p.h
#include "shared_p.h"
#include <functional>
#include <memory>
#include "DebugDelete.h"
template<typename T>
class shared_p
{
T *_ptr=nullptr;
std::size_t *_count=nullptr;
std::function<void(T*)> deleter{ DebugDelete() };
void free()
{
if (_ptr)
{
if (--*_count == 0)
{
delete _count;
deleter(_ptr);
}
_ptr = nullptr;
_count = nullptr;
}
}
public:
shared_p() = default;
shared_p(T *ptr, std::function<void(T*)> del = DebugDelete()) :
_ptr(ptr), deleter(del),_count(new std::size_t(1)) {}
shared_p(std::shared_ptr<T> &&sp, std::function<void(T*)> del = DebugDelete()) //16.29
{
if (sp.unique())
{
*this = shared_p(new T(*sp), del);
}
else
throw std::runtime_error("unique error!!");
}
shared_p(shared_p &&s)noexcept:_ptr(std::move(s._ptr)),_count(std::move(s._count)),deleter(std::move(s.deleter))
{
s._ptr = nullptr;
s._count = nullptr;
s.deleter = nullptr;
}
shared_p &operator=(shared_p &s)
{
if(_ptr!=nullptr)
free();
_ptr = s._ptr;
_count = s._count;
deleter = s.deleter;
++*_count;
return *this;
}
shared_p &operator=(shared_p &&s)
{
if (_ptr != nullptr)
free();
_ptr = s._ptr;
_count = s._count;
deleter = s.deleter;
s._count = nullptr;
s._ptr = nullptr;
s.deleter = nullptr;
return *this;
}
operator bool()const
{
return _ptr ? true : false;
}
T &operator*()const
{
return *_ptr;
}
T *operator->()const
{
return _ptr;
}
std::size_t use_count()const
{
return *_count;
}
T *get()const noexcept
{
return _ptr;
}
bool unique()const noexcept
{
return *_count == 1;
}
void swap(shared_p &s)
{
::__ExceptionPtrSwap(*this, s);
}
void reset()noexcept
{
free();
}
void reset(T *s, std::function<void(T*)> &del=DebugDelete())
{
if (_ptr != p)
{
free();
_ptr = s;
_count = new std::size_t(1);
deleter = del;
}
}
void reset(std::function<void(T*)> &del = DebugDelete())
{
deleter = del;
}
~shared_p()
{
free();
}
};
#pragma once //Bolb.h
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
#include <memory> //make_shared
#include "shared_p.h"
template<typename T> class Blob;
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class Blob
{
public:
friend bool operator==<T>(const Blob &l, const Blob &r);
typedef T value_type;
typedef typename std::vector<T>::size_type size_type; //把size_type视为类型名,忽略vector里同名的(如果有)静态变量
Blob();
Blob(std::initializer_list<T> il);
template<class U>
Blob(U b, U e);
size_type size()const { //返回元素数量
return data->size();
}
bool empty()const { //是否为空
return data->empty();
}
void push_back(const T &t) { //添加元素到末尾
data->push_back(t);
}
void push_back(T &&t) {
data->push_back(std::move(t));
}
void pop_back(); //弹出末尾元素
T &back(); //返回末尾元素的引用
T &operator[](size_type i); //返回第i个元素的引用
private:
shared_p<std::vector<T>> data;
void check(size_type i, const std::string &msg)const;
};
template<typename T>
void Blob<T>::check(size_type i, const std::string &msg)const {
if (i >= data->size())
throw std::out_of_range(msg);
}
template<typename T>
T &Blob<T>::back() {
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
T &Blob<T>::operator[](size_type i) {
check(i, "subscript out range");
return (*data)[i];
}
template<typename T>
void Blob<T>::pop_back() {
check(0, "pop_back on empty Blob");
data->pop_back();
}
template<typename T>
Blob<T>::Blob() :data(std::make_shared<std::vector<T>>()) {
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {
}
template<typename T>
bool operator==(const Blob<T> &l, const Blob<T> &r) {
if (l.data != r.data)
return false;
return true;
}
template<class T>
template<class U>
Blob<T>::Blob(U b, U e) :data(std::make_shared<std::vector<T>>(b, e))
{
}
#include "Blob.h"
int main()
{
using namespace std;
int vi[] = { 1,2,3,4,5,6 };
vector<int> vint(begin(vi), end(vi));
Blob<int> b(vint.begin(),vint.end());
for (typename Blob<int>::size_type i = 0; i != b.size(); ++i)
{
cout << b[i];
}
system("pause");
return 0;
}
16.31
在类内部定义的方法默认内联,unique_ptr内保存删除器的是一歌函数指针,所以并不会内联而是跳转
16.32
编译器通过实参的类型类推断模板的参数
16.33
一种是非const到const的转换
另外一种是数组或函数到指针的转换
16.34
a、非法,实参是两个不同的类型,前者为 char [3],后者为 char [6]
b、合法,T为const char [4]
16.35
a、合法,T为char,const char被转换为int
b、合法,T为double,float被转换为int
c、合法,T为char
d、非法,实参类型不统一,前者是double,后者是float
16.36
a、T为int*
b、T1和T2都是int*
c、T为const int*
d、都是const int*
e、非法,实参类型不相同,int*与const int*
f、T1为int*,T2为const int*
16.37
不能,该函数只能接受一个模板参数类型
16.38
该函数接收的实参是迭代器或指针,如果不给出实参类型,那么就不知道分配内存的大小
make_shared根据指定的实参类型分配合适的空间,并发返回一个指向这块空间的shared_ptr
16.39
compare<string>
16.40
合法、因为decltype会推导表达式的内容
所以需要改类型支持该表达式的操作:decltype(*beg+0);需要类型支持operator+操作
返回类型取决于该操作符operator的返回值
16.41
template<typename T>
auto sum(T &a,T &b)->decltype(a+b) //制定返回值的类型
{
return a+b;
}
16.42
a、i为左值,T为int&,val:int& &&折叠为int&
b、ci为左值,T为const int&,val:const int & &&折叠为const int&
c、i*ci为右值,T为int&&,val:T&& &&折叠为int&&
16.43
表达式i=ci最终留下的是左值,所以T为T&,val为int&
16.44
1、template<typename T> void g(T);
a、T为int,val为int
b、T为int,val为int,const被忽略,因为是按值传递
c、T为int,val为int,实参是右值,但是按值传递给形参
2、template<typename T> void g(const T&);
a、T为int,val为const int&
b、T为int,val为const int&
c、T为int&&,val为const int& &&,折叠为const int&
16.45
当实参为42时,编译器解析T为一个右值:int&&,所以val为:int&& &&,折叠后为int&&
当实参为int类型变量时,编译器解析T为一个左值:int&,所以val为:int& &&,折叠后为int&
在第一次传递时,T为int&&,这对于vector没有错误。
但是第二次传递时,T为int&,这样会出现一个错误:未初始化的左值
16.46
auto newcapacity = size() ? 2 * size() : 1; //当前空间的两倍大小
auto newdata = alloc.allocate(newcapacity); //分配并返回newcapacity个string对象大小的空间
auto dest = newdata;
auto elem = elements;//指向当前对象的头
for (size_t i = 0; i != size(); ++i)
{
alloc.construct(dest++, std::move(*elem++));//move会让elem指向的string对象放弃自己的内存管理权并返回,然后construct使用string的移动构造函数构建dest指向的地址
}
作用:把elem的所有元素移动到dest的空间里
16.47
#include <vector>
#include <iostream>
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 pp(int a, int &b)
{
std::cout << a << " " << ++b << std::endl;
}
void gv(int &a, int &b)
{
a += b;
b = a - b;
a = a - b;
}
int main()
{
using namespace std;
int a = 40, b = 86;
flip(pp,a, b);
flip(gv, a, b);
cout << a << " " << b << endl;
system("pause");
return 0;
}
16.49、16.50
#include <iostream>
template<typename T> void f(T t) {
std::cout << "f(T):" << t << std::endl;
}
template<typename T> void f(const T *t) {
std::cout << "f(const T *):" << t << " " << *t << std::endl;
}
template<typename T> void g(T t) {
std::cout << "g(T):" << t << std::endl;
}
template<typename T> void g(T *t) {
std::cout << "f(T *):" << t << " " << *t << std::endl;
}
int main()
{
using namespace std;
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42); //g(T)<span style="white-space:pre"> </span>const int更匹配T
g(p); //g(T*) <span style="white-space:pre"> </span>p是指针更匹配T*
g(ci); //g(T)
g(p2); //g(T*)
f(42); //f(T)
f(p); //f(T)
f(ci); //f(T)
f(p2); //f(const T*)<span style="white-space:pre"> </span>更加特例化
system("pause");
return 0;
}
16.51、16.52
#include <iostream>
#include <string>
template<typename T,typename... Args>
void foo(const T &t, Args... args)
{
std::cout << "Args:" << sizeof...(Args) << "\targs:" << sizeof...(args) << std::endl;
}
int main()
{
using namespace std;
int i = 0;
double d = 3.14;
string s = "c++ primer";
foo(i, s, 42, d); //Args:3 args:3
foo(i, 42, "hello"); //Args:2 args:2
foo(d, s); //Args:1 args:1
foo("hi"); //Args:0 args:0
foo("c++", '5', 2016, 4.2, i, s); //Agrs:5 args:5
system("pause");
return 0;
}
16.53
#include <iostream>
#include <string>
template<typename T>
std::ostream &print(std::ostream &os, const T &t)
{
return os << t;
}
template<typename T,typename... Args>
std::ostream &print(std::ostream &os,const T &t,const Args&... args)
{
os << t << ", ";
return print(os, args...);
}
int main()
{
using namespace std;
int a = 1;
double d = 2.2;
string s = "c++ primer";
print(cout, 42) << endl;
print(cout, 42, d) << endl;
print(cout, 42, d, s, "hello", 'w') << endl;
system("pause");
return 0;
}
16.54
缺少“<<”操作符的定义:
class Test
{};
...
Test t;
print(cout,t);//二进制“<<”: 没有找到接受“const aaa”类型的右操作数的运算符(或没有可接受的转换)
16.55
题目无法理解,会的同学请@我
16.56
#include <iostream>
#include <string>
#include <sstream>
template <typename T> std::string debug_rep(const T& t);
template <typename T> std::string debug_rep(T* p);
std::string debug_rep(const std::string &s);
std::string debug_rep(char* p);
std::string debug_rep(const char *p);
template<typename T>
std::string debug_rep(const T &s)
{
std::ostringstream ret;
ret << s;
return ret.str();
}
template<typename T>
std::string debug_rep(T *p)
{
std::ostringstream ret;
std::cout << "point:" << s;
if (p)
ret << " " << debug_rep(*p);
else
ret << "point is NULL!";
return ret.str();
}
template<typename T>
std::ostream &print(std::ostream &os, const T &t)
{
return os << t;
}
template<typename T,typename... Args>
std::ostream &print(std::ostream &os, const T &t, const Args&... args)
{
os << t << ", ";
return print(os, args...);
}
std::string debug_rep(const std::string &s)
{
return '"' + s + '"';
}
std::string debug_rep(char *p)
{
return debug_rep(std::string(p));
}
std::string debug_rep(const char *p)
{
return debug_rep(std::string(p));
}
template<typename... Args>
std::ostream &errorMsg(std::ostream &os, const Args... args)
{
return print(os, debug_rep(args)...);
}
int main()
{
using namespace std;
string str = "c++";
errorMsg(cout, str, "primer", 4, 8.6, '5');
system("pause");
return 0;
}
16.57
前者使用的是initialize_list,只能传递相同类型的实参,相比之下可变参数更灵活
16.58
#pragma once
#include <iostream>
#include <string>
#include <memory> //allocator
#include <utility> //move
#include <initializer_list>
#include <algorithm> //for_each
class StrVec
{
std::allocator<std::string> alloc;//为所有StrVec对象分配内存用
void chk_n_alloc() //如果剩余空间为0就分配新空间
{
if (size() == capacity())
reallocate();
}
std::pair<std::string *, std::string *> alloc_n_copy(const std::string *b, const std::string *e);//创建一个内容为b到e之间的元素的对象,并返回这个对象的一对头尾指针
void free();//释放所有alloc分配的所有内存
void reallocate();//移动当前对象的元素到2倍对象大小的新对象里
std::string *elements;
std::string *first_free;
std::string *cap;
public:
StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr){}
StrVec(std::initializer_list<std::string> il);
StrVec(const StrVec &s);
StrVec(StrVec &&s);
StrVec &operator=(StrVec &&s);
StrVec &operator=(const StrVec &s);
template<typename... Args> //16.58
void emplace_back(Args&&... args)
{
chk_n_alloc();
alloc.construct(first_free++, std::forward<Args>(args)...);
}
bool operator==(const StrVec &s)//14.16
{
if (size() != s.size())
return false;
auto it = elements, its = s.elements;
while (it != first_free)
{
if (*it++ != *its++)
return false;
}
return true;
}
bool operator!=(const StrVec &s)//14.16
{
return !(*this == s);
}
bool operator<(const StrVec &s)//14.18
{
if (size()>s.size())
return false;
else if (size() < s.size())
return true;
for (auto it = elements, its = s.elements; it != first_free; ++it, ++its)
{
if (*it == *its)
continue;
else if (*it > *its)
return false;
else
return true;
}
return false;
}
bool operator>(const StrVec &s)//14.18
{
return !(*this < s) && *this != s;
}
bool operator<=(const StrVec &s)//14.18
{
return !(*this > s);
}
bool operator>=(const StrVec &s)//14.18
{
return !(*this < s);
}
StrVec &operator=(std::initializer_list<std::string> il)
{
auto nobj = alloc_n_copy(il.begin(), il.end());
free();
elements = nobj.first;
first_free = cap = nobj.second;
return *this;
}
std::string &operator[](std::size_t n)
{
return elements[n];
}
const std::string &operator[](std::size_t n)const
{
return elements[n];
}
~StrVec();
void push_back(const std::string &s);//把string添加到尾后指针
size_t size()const
{
return first_free - elements;
}
size_t capacity()const
{
return cap - elements;
}
std::string *begin()const
{
return elements;
}
std::string *end()const
{
return first_free;
}
};
void StrVec::push_back(const std::string &s)
{
chk_n_alloc();//确保空间剩余
alloc.construct(first_free++, s);//在尾后构建一个s(s的拷贝构造函数构造),并把尾后指针first_free指向下一个
}
std::pair<std::string *, std::string *> StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
auto data = alloc.allocate(e-b);//分配并返回n个string对象的地址 string *
return{ data, std::uninitialized_copy(b, e, data) };//uninit_copy返回尾后指针string *
//把l~r之间的元素拷贝到data开始的地址,并返回data尾后,然后使用data(begin)和返回值(end)构建一个pair<string *,string *>
}
void StrVec::free()
{
if (elements)//如果不为空
{
for (auto p = first_free; p != elements;)
alloc.destroy(--p);//从最后一个元素开始向前摧毁,调用p的析构函数
//for_each(elements, first_free, [this](std::string *s){alloc.destroy(s); });//13.43
alloc.deallocate(elements, cap - first_free);//释放elements开始的n的string对象的内存
}
}
StrVec::StrVec(std::initializer_list<std::string> il)
{
auto newdata = alloc_n_copy(il.begin(), il.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec::StrVec(const StrVec &s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());//创建一个s的副本 值
elements = newdata.first;//把头指向新创建的副本的头
first_free = cap = newdata.second;//把尾后和内存尾指向副本的尾(以后调用会调用chk_n_alloc,不用担心剩余空间大小)
}
StrVec::StrVec(StrVec &&s) :elements(s.elements), first_free(s.first_free), cap(s.cap)
{
s.elements = s.first_free = s.cap = nullptr;
}
StrVec &StrVec::operator=(StrVec &&s)
{
if (this == &s)
return *this;
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = nullptr;
return *this;
}
StrVec::~StrVec()
{
free();//清理当前对象alloc分配的内存
}
StrVec &StrVec::operator=(const StrVec &s)
{
if (this == &s)
return *this;
auto data = alloc_n_copy(s.elements, s.first_free);
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
void StrVec::reallocate()
{
auto newcapacity = size() ? 2 * size() : 1; //当前空间的两倍大小
auto newdata = alloc.allocate(newcapacity); //分配并返回newcapacity个string对象大小的空间
auto dest = newdata;
auto elem = elements;//指向当前对象的头
for (size_t i = 0; i != size(); ++i)
{
alloc.construct(dest++, std::move(*elem++));//move会让elem指向的string对象放弃自己的内存管理权并返回,然后construct使用string的移动构造函数构建dest指向的地址
} //接受dest会指向newdata的尾后
free(); //移动完后释放当前对象指向的内存
elements = newdata; //指向新头
first_free = dest; //指向新尾后
cap = elements + newcapacity; //指向内存尾
}
16.59
16.60
可接受可变参数模板,转发其参数把初始化一个内存与没陪空间,返回一个shared_ptr
16.61
#include <memory>
#include <iostream>
#include <string>
template<typename T, typename... Args>
std::shared_ptr<T> make_shared(Args&&... args)
{
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
}
int main()
{
auto p = make_shared<int>(40);
std::cout << *p << std::endl;
auto cp = make_shared<std::string>(10, 'a');
std::cout << *cp << std::endl;
system("pause");
return 0;
}
16.62
#pragma once
#include <iostream>
#include <string>
class Sales_data
{
std::string bookNo;
unsigned units_sold;
double revenue;
double avg_price()const { return units_sold ? revenue / units_sold : 0; }
public:
Sales_data(const std::string &s=std::string(), unsigned n = 0, double p = 0) :bookNo(s), units_sold(n), revenue(p) {}
Sales_data(std::istream &is);
std::string isbn()const { return bookNo; }
Sales_data &operator+=(const Sales_data &s);
friend std::hash<Sales_data>;
friend std::ostream &operator<<(std::ostream &os, const Sales_data &s);
friend std::istream &operator>>(std::istream &is, Sales_data &s);
friend bool operator==(const Sales_data &ls, const Sales_data &rs);
friend Sales_data operator+(const Sales_data &ls, const Sales_data &rs);
friend std::ostream &print(std::ostream &os, const Sales_data &s);
friend std::istream &read(std::istream &is, Sales_data &s);
};
bool operator!=(const Sales_data &ls, const Sales_data &rs);
Sales_data add(const Sales_data &ls, const Sales_data &rs);
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);
}
};
}
#include "Sales_data.h"
Sales_data::Sales_data(std::istream &is)
{
is >> *this;
}
Sales_data &Sales_data::operator+=(const Sales_data &s)
{
units_sold += s.units_sold;
revenue += s.revenue;
return *this;
}
std::ostream &operator<<(std::ostream &os, const Sales_data &s)
{
os << s.isbn() << " " << s.units_sold << " " << s.revenue << " " << s.avg_price();
return os;
}
std::istream &operator>>(std::istream &is, Sales_data &s)
{
double price;
is >> s.bookNo >> s.units_sold >> price;
if (is)
s.revenue = s.units_sold*price;
else
s = Sales_data();
return is;
}
bool operator==(const Sales_data &ls, const Sales_data &rs)
{
return ls.bookNo == rs.bookNo&&ls.units_sold == rs.units_sold&&ls.revenue == rs.revenue;
}
bool operator!=(const Sales_data &ls, const Sales_data &rs)
{
return !(ls == rs);
}
Sales_data operator+(const Sales_data &ls, const Sales_data &rs)
{
Sales_data temp = ls;
temp += rs;
return temp;
}
Sales_data add(const Sales_data &ls, const Sales_data &rs)
{
Sales_data temp = ls;
temp += rs;
return temp;
}
std::ostream &print(std::ostream &os, const Sales_data &s)
{
os << s.isbn() << " " << s.units_sold << " " << s.revenue << " " << s.avg_price();
return os;
}
std::istream &read(std::istream &is, Sales_data &s)
{
double price;
is >> s.bookNo >> s.units_sold >> price;
s.revenue = s.units_sold*price;
return is;
}
#include <memory>
#include <unordered_set>
#include "Sales_data.h"
int main()
{
//! test for ex16.62
std::unordered_multiset<Sales_data> mset;
Sales_data sd("Bible", 10, 0.98);
mset.emplace(sd);
mset.emplace("C++ Primer", 5, 9.99);
for (const auto &item : mset)
std::cout << "the hash code of " << item.isbn()
<< ":\n0x" << std::hex << std::hash<Sales_data>()(item)
<< "\n";
system("pause");
return 0;
}
16.63、16.64
#pragma once
#include <vector>
#include <string>
#include <cstring>
template<typename T>
std::size_t count(const std::vector<T> &vec, T value)
{
std::size_t count = 0;
for (auto &x : vec)
count += (x == value) ? 1 : 0;
return count;
}
template<>
std::size_t count(const std::vector<char *> &vec, char *value)
{
std::size_t count = 0;
for (auto &x : vec)
count += (strcmp(x, value) == 0) ? 1 : 0;
return count;
}
#include <iostream>
#include "标头.h"
int main()
{
using namespace std;
//16.63
vector<double> dv = { 5,6,8,3,5,5,6,3,4 };
vector<int> iv = { 2,3,5,6,3,3,4,8,3,5,1 };
vector<string> sv = { "q","w","q","q","a","d","f","q" };
cout << count(dv, 5.0) << " " << count(iv, 3) << " " << count<string>(sv, "q");
//16.64
vector<char *> cpv = { "c++","primer","4th","hello","world","c++" };
cout << count<char *>(cpv, "c++");
system("pause");
return 0;
}
16.65
#pragma once
#include <sstream>
#include <string>
template<typename T>
std::string debug_rep(T *t)
{
std::ostringstream ret;
ret << t;
return ret.str();
}
template<>
std::string debug_rep(char *t)
{
return std::string(t);
}
template<>
std::string debug_rep(const char *t)
{
return std::string(t);
}
#include "标头.h"
#include <iostream>
int main()
{
using namespace std;
char c[] = "c++ primer 5";
const char *p = c;
cout << debug_rep(c) << endl;
cout << debug_rep(p) << endl;
system("pause");
return 0;
}
16.66
重载会改变匹配优先度
16.67
不会影响,
特化的模板匹配优先度和模板级别一致,还是非模板优先度最高
2016年4月9日23:34:23
过了那么久...连我自己都怀疑自己的耐心了