C++primer第十六章答案
16.1
当编译器实例化一个模板时,它会创建一个新的“实例”。模板使用实际的模板参数代替对应的模板参数。
16.2
template<typename T>
int compare(const T& lhs, const T& rhs)
{
if(lhs < rhs) return -1;
if(rhs < lhs) return 1;
return 0;
}
16.3
模板参数错误,Sales_data类没有定义"<"
16.4
template<typename I,typename V>
auto Find( I beg, I end ,const V& v)
{
for (; beg != end && *beg != v; ++beg);
return beg;
}
16.5
template<typename T,unsigned N>
void PrintArray(const T(&a)[N])
{
for (auto i : a)
{
std::cout << i << " ";
}
std::cout << std:: endl;
}
16.6
template<typename T, unsigned N >
T* Begin( T(&a)[N])
{
return a;
}
template<typename T, unsigned N >
T* End( T(&a)[N])
{
return a + N;
}
16.7
template<typename T, unsigned N >constexpr
int Size(const T(&a)[N])
{
return N;
}
16.8
因为相比<更多类定义了!=,这样做可以减少模板对参数的要求,模板程序应该尽量减少对实参类型的要求。
16.9
- 一个函数模板是一个公式,可以从中生成不同类型版本的该函数。
- 类模板是生成类的蓝图。类模板与函数模板的不同之处在于,编译器无法推断类模板的模板参数类型。相反,正如我们所见很多时候,要使用类模板,我们必须提供额外的信息放在模板名称后面的尖括号内。
16.10
当我们实例化一个模板类时,编译器会使用模板类型参数从模板中实例化一个特定类型的类。
16.11
模板类不是一个类型,我们在使用一个模板类时必须提供参数实例化出一个特定的类型。应该修改为
- void insert(ListItem< elemType> *ptr, elemType value);
- ListItem< elemType> *front, *end;
16.11
#pragma once
#include <vector>
#include<memory>
#include<string>
using namespace std;
template<typename Value> class BlobPtr;
template<typename Value>
class Blob
{
friend class BlobPtr<Value>;
public:
typedef typename vector<Value>::size_type size_type;
Blob(): data(make_shared<vector<Value>>()) {}
Blob(initializer_list<Value>il) :data(make_shared<vector<Value>>(il)) {}
size_type size()const { return data->size(); }
bool empty()const { return data->empty(); }
void push_back(const Value& v) { data->push_back(v); }
void push_back(Value && v) { data->push_back(move(v)); }
void pop_back();
Value& front();
Value& back();
Value& operator[](size_type n);
Value& front()const;
Value& back()const;
Value& operator[](size_type m)const;
private:
shared_ptr<vector<Value>> data;
void check(size_type, const string& msg);
};
template<typename Value>
void Blob<Value>::pop_back()
{
check(data->size()-1, "pop_back on empty Blob");
data->pop_back();
}
template<typename Value>
Value& Blob<Value>::back()
{
check(0, "back on empty Blob");
return data->back();
}
template<typename Value>
Value& Blob<Value>::back()const
{
check(0, "back on empty Blob");
return data->back();
}
template<typename Value>
Value& Blob<Value>::operator[](size_type n)
{
check(n, "subscript out of range");
return (*data)[n];
}
template<typename Value>
Value& Blob<Value>::operator[](size_type n)const
{
check(n, "subscript out of range");
return (*data)[n];
}
template<typename Value>
void Blob<Value>::check(size_type n, const string& msg)
{
if (n >= data->size())
throw std::out_of_range(msg);
}
template<typename Value>
Value& Blob<Value>::front()
{
check(0, "front on empty Blob");
return data->front();
}
template<typename Value>
Value& Blob<Value>::front()const
{
check(0, "front on empty Blob");
return data->front();
}
#pragma once
#include"Blob.h"
template <typename> class BlobPtr;
template <typename Value>
bool operator ==(const BlobPtr<Value>& lhs, const BlobPtr<Value>& rhs);
template <typename Value>
bool operator< (const BlobPtr<Value>& lhs, const BlobPtr<Value>& rhs);
template<typename Value>
class BlobPtr
{
friend bool operator< <Value>
(const BlobPtr<Value>& lhs, const BlobPtr<Value>& rhs);
friend bool operator==<Value>
(const BlobPtr<Value>& lhs, const BlobPtr<Value>& rhs);
public:
BlobPtr() :curr(0) {};
BlobPtr(Blob<Value>& a, size_t size = 0) :wptr(a.data), curr(size) {}
Value& operator*()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
BlobPtr& operator++()const;
BlobPtr& operator--()const;
shared_ptr<vector<Value>> check(size_t n, const string& msg)const;
weak_ptr<vector<Value>>wptr;
size_t curr;
};
template<typename Value>
BlobPtr<Value>& BlobPtr<Value>::operator++() const
{
check(curr, "increment past end of Blob");
--curr;
return *this;
}
template<typename Value>
inline BlobPtr<Value>& BlobPtr<Value>::operator--() const
{
check(curr, "decrement past begin of Blob");
--curr;
return *this;
}
template<typename Value>
shared_ptr<vector<Value>> BlobPtr<Value>::check(size_t n, const string& msg)const
{
auto ret = wptr.lock();
if (!ret) throw runtime_error("unbound StrBlobPtr");
if (n >= ret->size()) throw out_of_range(msg);
return ret;
}
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.i == rhs.i;
}
template<typename Value>
bool operator< (const BlobPtr<Value>& lhs, const BlobPtr<Value>& rhs)
{
if (lhs.wptr.lock() != rhs.wptr.lock()) {
throw runtime_error("ptrs to different Blobs!");
}
return lhs.i < rhs.i;
}
16.13
选择的是一对一的友好关系
16.14
#include <string>
#include <iostream>
template<unsigned H, unsigned W>
class Screen {
public:
typedef std::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);
friend std::ostream& operator<< (std::ostream& os, const Screen<H, W>& c)
{
unsigned int i, j;
for (i = 0; i < c.height; i++)
{
os << c.contents.substr(0, W) << std::endl;
}
return os;
}
friend std::istream& operator>> (std::istream& is, Screen& c)
{
char a;
is >> a;
std::string temp(H * W, a);
c.contents = temp;
return is;
}
private:
pos cursor = 0;
pos height = H, width = W;
std::string contents;
};
template<unsigned H, unsigned W>
inline Screen<H, W>& Screen<H, W>::move(pos r, pos c)
{
pos row = r * width;
cursor = row + c;
return *this;
}
16.16
#pragma once
#include <iostream>
#include<initializer_list>
using namespace std;
template<class T>
class Vec;
template<class T>
bool operator== (const Vec<T>& lhs, const Vec<T>& rhs);
template<class T>
bool operator!= (const Vec<T>& lhs, const Vec<T>& rhs);
template<class T>
bool operator> (const Vec<T>& lhs, const Vec<T>& rhs);
template<class T>
bool operator< (const Vec<T>& lhs, const Vec<T>& rhs);
template<typename T>
class Vec
{
friend bool operator==<T> (const Vec<T>& lhs, const Vec<T>& rhs);
friend bool operator!=<T> (const Vec<T>& lhs, const Vec<T>& rhs);
friend bool operator><T> (const Vec<T>& lhs, const Vec<T>& rhs);
template<typename T> friend bool operator< (const Vec<T>& lhs, const Vec<T>& rhs);
public:
Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) {};
Vec(initializer_list<T>il)
{
auto data = alloc_n_copy(il.begin(), il.end());
elements = data.first;
first_free = cap = data.second;
}
Vec(const Vec&);
Vec(Vec&& vec)noexcept :elements(vec.elements), first_free(vec.first_free), cap(vec.cap)
{
vec.elements = vec.first_free = vec.cap = nullptr;
}
Vec& operator=(Vec&& rhs)noexcept
{
if (this != &rhs)
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
~Vec();
Vec& operator=(initializer_list<T>);
Vec& operator= (const Vec&);
T& operator[](size_t n);
const T& operator[](size_t n)const;
void push_back(const 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; }
void reserve(size_t n);
void resize(size_t n, const T& s = " ");
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>
pair<T*, T*> Vec<T>::alloc_n_copy(const T* b, const T* e)
{
auto data = alloc.allocate(e - b);
return pair<T*, T*>(data, uninitialized_copy(b, e, data));
}
template<typename T>
void Vec<T>::free()
{
if (elements) {
auto b = first_free;
while (b != elements)
{
alloc.destroy(--b);
}
alloc.deallocate(elements, cap - elements);
}
}
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++));
}
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
template<typename T>
Vec<T>::Vec(const Vec& s)
{
auto data = alloc_n_copy(s.begin(), s.end());
elements = data.first;
first_free = cap = data.second;
}
template<typename T>
Vec<T>& Vec<T>::operator=(const Vec& rhs)
{
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
template<typename T>
void Vec<T>::push_back(const T& s)
{
chk_n_alloc();
alloc.construct(first_free++, s);
}
template<typename T>
Vec<T>::~Vec()
{
free();
}
template<typename T>
void Vec<T>::reserve(size_t n)
{
if (n < size())return;
auto newcapacity = n;
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata;
auto elem = elements;
for (size_t i = 0; i < size(); i++)
{
alloc.construct(dest++, move(*elem++));
}
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
template<typename T>
void Vec<T>::resize(size_t n, const T& s)
{
if (n > size()) {
if (n > capacity()) {
reserve(n);
}
for (size_t i = size(); i < n; ++i) {
alloc.construct(first_free++, s);
}
}
else if (n < size()) {
while ((elements + n) != first_free) {
alloc.destroy(--first_free);
}
}
}
template<typename T>
T& Vec<T>::operator[](size_t n)
{
return elements[n];
}
template<typename T>
const T& Vec<T>::operator[](size_t n)const
{
return elements[n];
}
template<typename T>
Vec<T>& Vec<T>::operator=(initializer_list<T>il)
{
auto p = alloc_n_copy(il.begin(), il.end());
free();
elements = p.first;
first_free = cap = p.second;
return *this;
}
template<typename T>
bool operator== (const Vec<T>& lhs, const Vec<T>& rhs)
{
if (lhs.size() != rhs.size()) {
return false;
}
else {
auto l_iter = lhs.begin();
auto r_iter = rhs.begin();
for (l_iter, r_iter; l_iter != lhs.end(); ++l_iter, ++r_iter) {
if (*l_iter != *r_iter) {
return false;
}
}
}
return true;
}
template<typename T>
bool operator!= (const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const Vec<T>& lhs, const Vec<T>& rhs)
{
return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template<typename T>
bool operator>(const Vec<T>& lhs, const Vec<T>& rhs)
{
return lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}
16.17
没有什么不同,当我们希望通知编译器一个名字表示类型时,必须使用关键字typename,而不能使用class。
16.18
- (a)少了个typename
- (b)T应该为类型,不能作为变量,
- (c)内联标识符要放到模板参数的尖括号后
- (d)错误,没有提供返回类型
- (e)正确,模板参数会隐藏外部同名类型参数
template <typename T, typename U, typename V> void f1(T, U, V);
template <typename T> T f2(T&);
template <typename T> inline T foo(T, unsigned int*);
template <typename T> T f4(T, T);
typedef char Ctype;
template <typename Ctype> Ctype f5(Ctype a);
16.19
当我们希望通知编译器一个名字表示类型时,必须使用关键字typename;
循环中的typename是必须的。
#include <iostream>
#include <vector>
using namespace std;
template<typename Container>
void PrintContainer(const Container & container, ostream& os)
{
for (typename Container::size_type i=0; i != container.size(); i++)
{
os << container[i] << " ";
}
}
16.20
template<typename Container>
void PrintContainer(const Container& container, ostream& os)
{
for (auto beg=container.cbegin(); beg != container.cend(); beg++)
{
os << *beg << " ";
}
}
16.21
#pragma once
#include <iostream>
class DebugDelete
{
DebugDelete(std::ostream& s = std::cerr) :os(s) {};
template<typename T>
void operator()(T* p)const { os << "deleting unique_ptr" << std::endl; delete p }
private:
std::ostream os;
};
16.22
略
16.23
略
16.24
template<typename Value>
template<typename Iter>
Blob<Value>::Blob(const Iter& beg, const Iter& end)
{
data = make_shared<vector<Value>>(beg, end);
}
16.28
#include <iostream>
#include<functional>
#include"Delete.h"
using namespace std;
template<typename T>
class SharedPointer;
template<typename T>
void swap(SharedPointer<T>& lhs, SharedPointer<T>& rhs)
{
swap(lhs.pointer, rhs.pointer);
swap(lhs.ref_count, rhs.ref_count);
swap(lhs.deleter, rhs.deleter);
}
template<typename T>
class SharedPointer
{
public:
SharedPointer() :pointer(nullptr), ref_count(new size_t(1)),deleter(Delete()) {}
SharedPointer(T* p):pointer(p),ref_count(new size_t(1)),deleter(Delete()) {}
SharedPointer(const SharedPointer& sp):pointer(sp.pointer),ref_count(sp.ref_count),deleter(sp.deleter)
{
++(*ref_count);
}
SharedPointer(SharedPointer&& sp)noexcept :pointer(sp.pointer), ref_count(sp.ref_count), deleter(move(sp.deleter))
{
sp.ref_count = nullptr;
sp.pointer = nullptr;
}
SharedPointer& operator=(const SharedPointer& sp)
{
++(*sp.ref_count);
decrement_and_destroy();
pointer = sp.pointer;
ref_count = sp.ref_count;
deleter = sp.deleter;
return *this;
}
SharedPointer& operator=( SharedPointer&& sp)
{
swap(*this, sp);
sp.decrement_and_destroy();
return *this;
}
explicit operator bool()const { return pointer ? true : false; }//提供SharedPointer到bool的显示转换
T& operator*() { return *pointer; }
T* operator->() const{return &*pointer;}
size_t use_count()const { return *ref_count; }
T* get() { return pointer; }
bool unique()const { return *ref_count == 1; }
void swap(SharedPointer& rhs)
{
::swap(*this, rhs);
}
void reset() { decrement_and_destroy(); }
void reset(T* ptr)
{
if (pointer!=ptr)
{
decrement_and_destroy();
pointer = ptr;
ref_count = new std::size_t(1);
}
}
void reset(T* ptr,const function<void(T*)>&d)
{
reset(ptr);
deleter = d;
}
~SharedPointer() { decrement_and_destroy(); }
private:
T* pointer;
size_t* ref_count;
function<void(T*)> deleter;
void decrement_and_destroy()
{
if (pointer && --*ref_count == 0)
{
delete pointer;
delete ref_count;
}
else if (!pointer)
{
delete ref_count;
}
ref_count = nullptr;
pointer = nullptr;
}
};
#include"Delete.h"
template<typename T, typename D>
class UniquePointer;
template<typename T,typename D>
void swap(UniquePointer<T,D>& lhs, UniquePointer<T,D>& rhs)
{
std::swap(lhs.pointer, rhs.pointer);
std::swap(lhs.deleter, rhs.deleter);
}
template<typename T,typename D=Delete()>
class UniquePointer
{
friend void swap<T, D>(UniquePointer<T, D>& lhs, UniquePointer<T, D>& rhs);
public:
UniquePointer(const UniquePointer&) = delete;
UniquePointer& operator = (const UniquePointer&) = delete;
UniquePointer() :pointer(nullptr) {}
explicit UniquePointer(T* ptr) :pointer(ptr) {}
UniquePointer(T* ptr, D d) :pointer(ptr), deleter(d) {}
UniquePointer(UniquePointer&& up) noexcept: pointer(up.pointet) {up.pointer = nullptr;}
UniquePointer& operator =(UniquePointer&& rhs) noexcept
{
if (rhs.pointer != pointer)
{
deleter(pointer);
pointer = nullptr;
::swap(*this, rhs);
}
return *this;
}
UniquePointer& operator =(std::nullptr_t n) noexcept
{
if (n == nullptr)
{
deleter(pointer); pointer = nullptr;
}
return *this;
}
T& operator *() const { return *pointer; }
T* operator ->() const { return &this->operator *(); }
operator bool() const { return pointer ? true : false; }
T* get() const noexcept { return pointer; }
void swap(UniquePointer<T, D>& rhs) { ::swap(*this, rhs); }
void reset() noexcept { deleter(pointer); pointer = nullptr; }
void reset(T* p) noexcept { deleter(pointer); pointer = p; }
T* release()
{
T* ret = pointer;
pointer = nullptr;
return ret;
}
~UniquePointer() { deleter(pointer); }
private:
T* pointer;
D deleter = D();
};
16.29
略
16.30
略
16.31
编译器会在编译时就把默认删除器设置为DebugDelete。
16.32
从函数参数推断模板参数这一过程被称为模板实参推断。在模板参数推导过程中,编译器在调用中使用参数类型来查找模板参数,该参数生成与给定匹配的函数版本调用。
16.33
- 从非常量引用或指针向非常量引用或指针的转化
- 当参数为非引用时,数组和函数可以转化为指针
16.34
- 不合法,传递的是char (&a)[3]和char(&b)[6]
- 合法
16.35
- (a)合法,T为char
- (b)合法,T为double
- ( c)合法,T为char
- (d)不合法,两个实参类型不同
16.36
- a. f1(int*,int*);
- b. f2(int*,int*);
- c. f1(const int*,const int*);
- d. f2(const int*,const int*);
- e.错误
- f. f2( int*,const int*);
16.37
可以,显式指定实参double,int将被转化为double
16.38
如果没有显式指定模板实参,allocator不知道应该分配多少内存空间给shared_ptr。
16.39
compare< string>(“1”, “2”)
16.40
合法,取决于operator+的返回值类型
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)T为const int&,val也为const int&
- (c)T为int,val为int&&
16.43
operator=会返回一个int&,模板参数为int&
16.44
如果函数声明为T
(a)int
(b)int const被忽略
(c)int
如果函数声明为const T&
(a)T为int,val为const int&
(b)T为int,val为const int&
(c)T为int,val为const int&
16.45
用字面值常量调用g会实例化
void g(int&&val){vecotr<int&&>v;}
用int调用g会实例化
void g(int&val){vector<int&>v;}//报错,容器不能存储引用
16.46
move函数会将*elem这个左值引用强制类型转换为右值引用
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> std::string Debug_rep(const T& t);
template <typename T> std::string Debug_rep(T* p);
string Debug_rep(const std::string& s);
string Debug_rep(char* p);
string Debug_rep(const char* p);
template<typename T>
string Debug_rep(const T& s)
{
ostringstream ret;
ret << s << endl;
return ret.str();
}
template<typename T>
string Debug_rep(T* s)
{
ostringstream ret;
cout << "pointer:" << s << endl;
if (s)
cout << Debug_rep(*p) << endl;
else
cout << "null pointer" << endl;
}
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));
}
16.49
- g(42) T=int template< typename T> void g(T);
- g( p) T=int template< typename T> void g(T*)
- g(ci) T=const int template< typename T> void g(T)
- g(p2) T=const int template< typename T> void g(T*)
- f(42) T=int template< typename T> void f(T)
- f§ T=int* template< typename T> void f(T)
- f(ci) T=const int template< typename> void f(T)
- f(p2) T=int template< typename> void f(const T*)
16.50
略
16.51
16.52
#include <iostream>
template<typename T, typename ...Args>
void foo(T t, Args ...args)
{
std::cout << sizeof...(Args) << std::endl;
std::cout << sizeof...(args) << std::endl;
}
int main()
{
int i = 0;
double d = 3.14;
std::string s = "how";
foo(i, s, 42, d); // sizeof...(Args)=3 sizeof...(args)=3
foo(s, 42, "hi"); // sizeof...(Args)=2 sizeof...(args)=2
foo(d, s); // sizeof...(Args)=1 sizeof...(args)=1
foo("hi"); // sizeof...(Args)=0 sizeof...(args)=0
foo(i, s, s, d); // sizeof...(Args)=3 sizeof...(args)=3
}
16.53
#include <iostream>
using namespace std;
template<typename T>
ostream& print(ostream&, const T&);
template<typename T,typename...Args>
ostream& print(ostream& os, const T& t, const Args...rest)
{
os << t << ",";
return print(os, rest...);
}
template<typename T>
ostream& print(ostream&os, const T&t)
{
return os << t ;
}
int main()
{
int i = 4;
int* pi = &i;
print(cout,1);
cout << endl;
print(cout, 1.1, 2);
cout << endl;
print(cout, "Numbers:",1,2,3,i,pi);
}
16.54
二进制“<<”: 没有找到接受“const T”类型的右操作数的运算符(或没有可接受的转换)
16.55
代码不能执行,显示“print”: 未找到匹配的重载函数和“std::ostream &print(std::ostream &,const T &,const Args…)”: 应输入 3 个参数,却提供了 1 个
16.56
#include"Debug_rep.h"
#include"print.h"
template<typename ...Args>
ostream& errorMsg(ostream&os,const Args...rest)
{
return print(os, Debug_rep(rest)...);
}
int main()
{
errorMsg(cout, "1", 1, 3.14);
}
16.57
可变参数版本的代码灵活,可以使用不同类型的参数,但是代码比较复杂,不方便调试。原版的代码参数为initializer_list,只能接受同一种类型元素,或者是可以转换的类型,但是代码简单,方便调试。
16.58
template<typename T>
template<typename ...Args>
inline void Vec<T>::emplace_back(Args&& ...args)
{
chk_n_alloc();
alloc.construct(first_free++, forward<Args>(args)...);
}
16.59
1.转发参数包
2.由于s是左值,传入后由于实参为右值引用,且我们使用forward传递这些实参,因此s的类型信息将会完整的保存,一个左值参数调用construct,将会调用拷贝构造函数创建一个string。
16.60
make_shared函数是一个可变模板参数,它会把参数转发给初始化对象的构造函数,通过动态分配内存空间创建一个指针,在最后将原始指针包装为shared_ptr返回。
16.61
template<typename T,typename ...Args>
shared_ptr<T> Make_shared(Args&&...args)
{
return shared_ptr<T>(new T(forward<Args>(args)...));
}
16.62
#include <string>
#include <vector>
#include <iostream>
#include <unordered_set>
using namespace std;
class Sales_data
{
friend bool operator==(const Sales_data&, const Sales_data&);
friend std::hash<Sales_data>;
private:
string isbn;
unsigned units_sold = 0;
double revenue = 0.0;
public:
Sales_data(string isbn, unsigned units_sold, double revenue) : isbn(isbn), units_sold(units_sold), revenue(revenue) {}
double avg_price() { return revenue / units_sold; }
void print() { std::cout << "name=" << isbn << " aver_price= " << avg_price() << std::endl; }
string prints() { return string("name=") + isbn + " aver_price= " + to_string(avg_price()); }
};
bool operator==(const Sales_data& a, const Sales_data& b)
{
return (a.isbn == b.isbn) && (a.revenue == b.revenue) && (a.units_sold == b.units_sold);
}
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.isbn) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue);
}
};
}
16.63
16.64
#include <iostream>
#include<vector>
#include<algorithm>
template<typename T>
size_t count_vec(std::vector<T>const &vec, const T t)
{
return std::count(vec.cbegin(), vec.cend(), t);
}
template<>
size_t count_vec(std::vector<const char*>const& vec, const char* t)
{
return std::count(vec.cbegin(), vec.cend(), t);
}
int main()
{
std::vector<double> vd = { 1.1, 1.1, 2.3, 4 };
std::cout << count_vec(vd, 1.1) << std::endl;
std::vector<const char*> vcc = { "alan", "alan", "alan", "alan", "moophy" };
std::cout << count_vec(vcc, "alan") << std::endl;
}
16.65
template<typename T>
string Debug_rep(const char* s)
{
string ret(s);
return s;
}
template<typename T>
string Debug_rep( char* s)
{
string ret(s);
return s;
}
16.66
重载会改变函数匹配顺序,而特例化的实质是实例化一个模板函数,不会改变函数匹配顺序。
16.67
不会影响,特例化只是实例化一个模板函数,并没用重载函数,不会改变函数匹配。