C++primer第十六章答案

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
不会影响,特例化只是实例化一个模板函数,并没用重载函数,不会改变函数匹配。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值