《C++primer(第五版)》学习之路-第十六章:模板与泛型编程

 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:[email protected]


16.1 定义模板


1.模板定义以关键字template开始,后跟一个模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用小于号(<)和大于号(>)包围起来。在模板定义中,模板参数列表不能为空。


2.模板知道实力化时才会生成代码,这一特性影响了我们何时才睡获知模板内代码的编译错误。通常,编译器会在三个阶段报告错误。

第一个阶段是编译模板本身时。在这个阶段,编译器通常不会发现很多错误。编译器可以检查语法错误,例如忘记分号或者变量名拼错等,但也就这么多了。

第二个阶段是编译器遇到模板使用时。在此阶段,编译器仍然没有很多可检查的。对于函数模板调用,编译器通常会检查实参数目是否正确。它还能检查参数类型是否匹配。对于类模板,编译器可以检查用户是否提供了正确数目的模板实参,但也仅限于此了。

第三个阶段是模板实例化时,只有在这个阶段才能发现类型相关的错误。依赖于编译器如何管理实例化,这类错误可能在链接时才报告。


3.一个类(无论是普通类还是类模板)可以包含本身是模板的成员函数。这种成员被称为成员模板。成员模板不能是虚函数。


16.2 模板实参推断


1.从函数实参来确定模板实参的过程被称为模板实参推断。在模板实参推断过程中,编译器使用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配。


2.顶层const无论实在形参中还是在实参中,都会被忽略。在其他类型转换中,能在调用中应用于函数模板的包括如下两项。

⑴const转换:可以将一个非const对象的引用(或指针)传递给一个const的引用(或指针)形参。

⑵数组或函数指针转换:如果函数形参不是引用类型,则可以对数组或函数类型的实参应用正常的指针转换。一个数组实参可以转换为一个指向其首元素的指针。类似的,一个函数实参可以转换为一个该函数类型的指针。


3.

如果一个函数参数是一个指向模板类型参数的右值引用(如T&&),则它可以被绑定到一个左值

如果实参是一个左值,则推断出的模板实参类型将是一个左值引用,且函数参数将被实例化为一个左值引用参数(T&)


16.3 重载与模板


1.函数匹配规则会在以下几个方面受到影响:

⑴对于一个调用,其候选函数包括所有模板实参推断成功的函数模板实例

⑵候选的函数模板总是可行的,因为模板实参推断会排除任何不可行的模板

⑶与往常一样,可行函数(模板与非模板)按类型转换来排序。当然,可以用于函数模板调用的类型转换是非常有限的。

⑷与往常一样,如果恰有一个函数提供比任何其他函数都更好的匹配,则选择此函数。但是如果有多个函数提供同样更好的匹配,则:

-如果同样好的函数中只有一个是非模板函数,则选择此函数

-如果同样好的函数中没有非模板函数,而有多个函数模板,且其中一个模板比其他模板更特丽花,则选择此模板

-否则,此调用有歧义


16.4 可变参数模板


1.一个可变参数模板,就是一个接受可变数目参数的模板函数或模板类。可变数目的参数被称为参数包。存在两种参数包:模板参数包,表示零个或多个模板参数;函数参数包,表示零个或多个函数参数。


PS:部分练习答案


练习16.4

#include 
#include 
#include 
#include 


template
iteratorT find(const iteratorT& first, const iteratorT& last,const valueT& value )
{
	auto iter = first;
	while(iter != last && *iter != value) ++iter;
	return iter;
}

int main()
{
	std::vector vi = {1,2,3,4,5,6,7,8,9};
	auto it = find(vi.cbegin(), vi.cend(), 5);
	std::cout << *it << std::endl;

	std::list l = {"aa","bb","cc","dd","ee","ff","gg"};
	std::list::const_iterator itL = find(l.cbegin(), l.cend(), "ee");
	std::cout << *itL << std::endl;

	return 0;
}

练习16.5

#include 
#include 

template
void print(const Arr& a)
{
	for(const auto& elem : a)
	std::cout << elem << std::endl;
}

int main()
{
	std::string p[] = {"ssss","aaa","ssssss"};
	char c[] = {'a','b','c','d'};
	int  i[] = {1};
	print(i);
	print(c);
	print(p);

	std::cout << "\nexit normally\n";
	return 0;
}

练习16.6

#include 
#include 
#include 
#include 

template
T* begin(const T(&arr)[size])
{
	return arr;
}

template
T* end(const T (&arr)[size])
{
	return arr + size;
}

int main()
{
	std::string s[] = {"sssss","ss","ss","ssssszzzz"};
	std::cout << *(begin(s)+1) << std::endl;
	std::cout << *(end(s) - 1) << std::endl;
	return 0;
}

练习16.7

#include 
#include 
#include 
#include 

template
constexpr unsigned getSize(const T(&)[size])
{
	return size;
}

int main()
{
	std::string s[] = {"sss"};
	std::cout << getSize(s) << std::endl;

	char c[] = "s";
	std::cout << getSize(c) << std::endl;
	return 0;
}

练习16.16

vec.h

#ifndef VEC_H
#define VEC_H

#include 

template
class Vec
{
	public:
		Vec():element(nullptr), first_free(nullptr), cap(nullptr) { }
		Vec(std::initializer_list l);
		Vec(const Vec& v);

		Vec& operator =(const Vec& rhs);

		~Vec();

		//! memmbers
		void push_back(const T& t);

		std::size_t size() const
		{
			return first_free - element;
		}
		std::size_t capacity()const
		{
			return cap - element;
		}

		T* begin() const
		{
			return element;
		}
		T* end()   const
		{
			return first_free;
		}

		void reserve(std::size_t n);

		void resize(std::size_t n);
		void resize(std::size_t n, const T& t);

	private:
		//! data members
		T* element;
		T* first_free;
		T* cap;

		std::allocator alloc;

		//! utillities
		void reallocate();
		void chk_n_alloc()
		{
			if(size()==capacity()) reallocate();
		}
		void free();

		void wy_alloc_n_move(std::size_t n);

		std::pair alloc_n_copy(T* b, T* e);
};


//! copy constructor
template
Vec::Vec(const Vec &v)
{
	std::pair newData = alloc_n_copy(v.begin(), v.end());
	element = newData.first;
	first_free = cap = newData.second;
}


//! constructor that takes initializer_list
template
Vec::Vec(std::initializer_list l)
{
	//! allocate memory as large as l.size()
	T* const newData = alloc.allocate(l.size());

	//! copy elements from l to the address allocated
	T* p = newData;
	for(const auto &t : l)
		alloc.construct(p++, t);

	//! build data structure
	element = newData;
	first_free = cap = element + l.size();
}


//! operator =
template
Vec& Vec::operator =(const Vec& rhs)
{
	//! allocate and copy first to protect against self_assignment
	std::pair newData = alloc_n_copy(rhs.begin(), rhs.end());

	//! destroy and deallocate
	free();

	//! update data structure
	element = newData.first;
	first_free = cap = newData.second;

	return *this;
}


//! destructor
template
Vec::~Vec()
{
	free();
}

template
void Vec::push_back(const T &t)
{
	chk_n_alloc();
	alloc.construct(first_free++, t);
}

template
void Vec::reserve(std::size_t n)
{
	//! if n too small, just return without doing anything
	if(n <= capacity()) return;

	//! allocate new memory and move data from old address to the new one
	wy_alloc_n_move(n);
}

template
void Vec::resize(std::size_t n)
{
	resize(n, T());
}

template
void Vec::resize(std::size_t n, const T &t)
{
	if(n < size())
	{
		//! destroy the range [element+n, first_free) using destructor
		for(auto p = element + n; p != first_free;   )
			alloc.destroy(p++);
		//! update first_free to point to the new address
		first_free = element + n;
	}
	else if(n > size())
	{
		for (auto i = size(); i != n; ++i)
			push_back(t);
	}
}

template
std::pair
Vec::alloc_n_copy(T *b, T *e)
{
	//! calculate the size needed and allocate space accordingly
	T* data = alloc.allocate(e-b);
	return { data, std::uninitialized_copy(b, e, data)};
}

template
void Vec::free()
{
	//! if not nullptr
	if(element)
	{
		//! destroy it in reverse order.
		for(auto p = first_free; p != element;    )
			alloc.destroy(--p);

		alloc.deallocate(element,capacity());
	}
}

template
void Vec::wy_alloc_n_move(std::size_t n)
{
	//! allocate as required.
	std::size_t newCapacity = n;
	T* newData = alloc.allocate(newCapacity);

	//! move the data from old place to the new one
	T* dest = newData;
	T* old  = element;
	for(std::size_t i = 0; i != size(); ++i)
		alloc.construct(dest++, std::move(*old++));

	free();

	//! update data structure
	element     =   newData;
	first_free  =   dest;
	cap         =   element + newCapacity;
}

template
void Vec::reallocate()
{
	//! calculate the new capacity required
	std::size_t newCapacity = size() ? 2 * size() : 1;

	//! allocate and move old data to the new space
	wy_alloc_n_move(newCapacity);
}



#endif

main.cpp

#include "vec.h"
#include 
#include 

int main()
{
	Vec v = {1,2,3,4,5};

	Vec v2;

	v2 = v;
	std::cout << v2.capacity() << "\n";
	v2.push_back(99);
	v2.resize(2,2);

	for (auto t : v2)
		std::cout << t << " ";


	std::cout << v2.capacity() << "\n";

	return 0;
}

练习16.19 & 16.20

#include 
#include 
#include 

//! ex16.19 using size() to control the loop
template
std::ostream & print(Container &c, std::ostream &os)
{
	typedef typename Container::size_type size_type;

	auto it = c.begin();
	for(size_type i = 0; i!= c.size(); ++i)
		os << *it++ << "\n";

	return os;
}

//! ex16.20 using iterator to control the loop
template
std::ostream& print2(Container& c, std::ostream &os)
{
	for (auto it = c.begin(); it != c.end(); ++it)
		os << *it << "\n";

	return os;
}
int main()
{
	std::vector v = {1,23,6,4,5,7,4};
	std::list l = {"ss","sszz","saaas","s333s","ss2","sss"};
	print2(v, std::cout);
	print2(l, std::cout);

	return 0;
}

练习16.21 & 16.22

DebugDelete.h

#ifndef DEBUGDELETE_H
#define DEBUGDELETE_H

#include 

class DebugDelete
{
	public:
		DebugDelete(std::ostream& s = std::cerr) : os(s) { }
		template
		void operator() (T* p) const
		{
			os << "deleting unique_ptr" << std::endl;
			delete p;
		}

	private:
		std::ostream& os;
};
#endif

StrBlob.h

#ifndef STRBLOB_H
#define STRBLOB_H

#include 
#include 
#include 
#include 
#include 

class StrBlobPtr;

class StrBlob
{
		friend class StrBlobPtr;
	public:
		typedef std::vector::size_type size_type;

		StrBlob() : data(std::make_shared>()) { }
		StrBlob(std::initializer_list il);

		size_type size() const
		{
			return data->size();
		}
		bool empty() const
		{
			return data->empty();
		}
		void push_back(const std::string &t)
		{
			data->push_back(t);
		}
		void pop_back();

		std::string& front();
		std::string& back();

		StrBlobPtr begin();
		StrBlobPtr end();
	private:
		std::shared_ptr> data;
		void check(size_type i, const std::string &msg) const;
};

inline StrBlob::StrBlob(std::initializer_list il):	data(std::make_shared>(il)) { }

class StrBlobPtr
{
		friend bool eq(const StrBlobPtr&, const StrBlobPtr&);
	public:
		StrBlobPtr(): curr(0) { }
		StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }

		StrBlobPtr(const StrBlob &a, const size_t sz = 0) : wptr(a.data), curr(sz) { }

		std::string& deref() const;
		StrBlobPtr& incr();
		StrBlobPtr& decr();
	private:
		std::shared_ptr> check(std::size_t, const std::string&) const;

		std::weak_ptr> wptr;
		std::size_t curr;
};

inline
std::string& StrBlobPtr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

inline
std::shared_ptr>
                                       StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
	auto ret = wptr.lock();
	if (!ret)
		throw std::runtime_error("unbound StrBlobPtr");

	if (i >= ret->size())
		throw std::out_of_range(msg);
	return ret;
}

inline
StrBlobPtr& StrBlobPtr::incr()
{
	check(curr, "increment past end of StrBlobPtr");
	++curr;
	return *this;
}

inline
StrBlobPtr& StrBlobPtr::decr()
{
	--curr;
	check(-1, "decrement past begin of StrBlobPtr");
	return *this;
}

inline
StrBlobPtr
StrBlob::begin()
{
	return StrBlobPtr(*this);
}

inline
StrBlobPtr
StrBlob::end()
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}

// named equality operators for StrBlobPtr
inline
bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
	if (l == r)
		return (!r || lhs.curr == rhs.curr);
	else
		return false;
}

inline
bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	return !eq(lhs, rhs);
}
#endif

wy_textquery.h

#ifndef WY_TEXTQUERY_H
#define WY_TEXTQUERY_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 

class wy_queryResult;

class wy_textQuery
{
	public:
		typedef std::shared_ptr> sp_file_Tp;
		typedef std::shared_ptr>> sp_Qmap_Tp;

		wy_textQuery() = default;
		wy_textQuery(std::ifstream &fin);

		wy_queryResult
		query(const std::string &qWord) const;

	private:
		sp_file_Tp sp_fileData = nullptr;

		sp_Qmap_Tp sp_queryMap = nullptr;
};

#endif

wy_textquery.cpp

#include "wy_textquery.h"
#include "wy_queryresult.h"
#include "DebugDelete.h"
#include 
#include 

wy_textQuery::wy_textQuery(std::ifstream &fin) :
	sp_fileData(new std::vector(), DebugDelete() ),
	sp_queryMap(new std::map>(), DebugDelete())
{
	std::string line;
	while(std::getline(fin, line))
		sp_fileData->push_back(line);

}

wy_queryResult wy_textQuery::query(const std::string &qWord) const
{
	std::size_t counter = 0;

	for(std::size_t i=0; i != sp_fileData->size(); ++i)
	{
		std::stringstream lineStream((*sp_fileData)[i]);
		std::string word;
		while(lineStream >> word)
		{
			if(!word.compare(qWord))
			{
				++counter;
				(*sp_queryMap)[qWord].insert(i);
			}
		}
	}
	wy_queryResult qResult(counter, qWord, sp_fileData, sp_queryMap);

	return qResult;
}

wy_queryresult.h

#ifndef WY_QUERYRESULT_H
#define WY_QUERYRESULT_H
#include "wy_textquery.h"

class wy_queryResult
{
	public:
		wy_queryResult() = default;

		wy_queryResult(const wy_queryResult &qr);

		wy_queryResult(std::size_t c, const std::string &str,
		               const wy_textQuery::sp_file_Tp &sp_f,
		               const wy_textQuery::sp_Qmap_Tp &sp_m);

		std::size_t
		getCounter() const
		{
			return counter;
		}

		std::string
		getQueryWord() const
		{
			return queryWord;
		}

		wy_textQuery::sp_file_Tp
		getSp_file() const
		{
			return sp_file;
		}

		wy_textQuery::sp_Qmap_Tp
		getSp_Qmap() const
		{
			return sp_Qmap;
		}

	private:

		std::size_t counter = 0;

		std::string queryWord = "";

		wy_textQuery::sp_file_Tp sp_file = nullptr;

		wy_textQuery::sp_Qmap_Tp sp_Qmap = nullptr;
};

void print(std::ostream &os, const wy_queryResult &qr);

#endif

wy_queryresult.cpp

#include "wy_queryresult.h"

inline wy_queryResult::wy_queryResult(const wy_queryResult &qr):
	counter(qr.getCounter()), queryWord(qr.getQueryWord()),
	sp_file(qr.getSp_file()), sp_Qmap(qr.getSp_Qmap())
{
}

wy_queryResult::wy_queryResult(std::size_t c, const std::string &str,
                               const wy_textQuery::sp_file_Tp &sp_f,
                               const wy_textQuery::sp_Qmap_Tp &sp_m) :
	counter(c), queryWord(str), sp_file(sp_f), sp_Qmap(sp_m)
{
}

void print(std::ostream &os, const wy_queryResult &qr)
{
	const std::string queryWord = qr.getQueryWord();

	os << "The word [" <

main.cpp

#include 
#include 
#include 

#include "DebugDelete.h"
#include 

#include "wy_queryresult.h"
#include "wy_textquery.h"

int main()
{
	return 0;
}

练习16.24

#ifndef BLOB_H
#define BLOB_H
#include 
#include 

template class Blob
{
	public:
		typedef T value_type;
		typedef typename std::vector::size_type size_type;

		Blob();
		Blob(std::initializer_list il);

		template
		Blob(It b, It 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);

		const T& back() const;
		const T& operator [](size_type i) const;

	private:
		std::shared_ptr> data;
		void check(size_type i, const std::string &msg) const;
};

template
Blob::Blob() : data(std::make_shared>())
{}

template
Blob::Blob(std::initializer_list il): data(std::make_shared>(il)) { }

template
template
Blob::Blob(It b, It e) :
	data(std::make_shared>(b,e))
{}

template
void Blob::check(size_type i, const std::string &msg) const
{
	if(i >= data->size())
		throw std::out_of_range(msg);
}

template
T& Blob::back()
{
	check(0,"back on empty Blob");
	return data->back();
}

template
const T& Blob::back() const
{
	check(0,"back on empty Blob");
	return data->back();
}


template
T& Blob::operator [](size_type i)
{
	check(i,"subscript out of range");
	return (*data)[i];
}


template
const T& Blob::operator [](size_type i) const
{
	check(i,"subscript out of range");
	return (*data)[i];
}

template
void Blob::pop_back()
{
	check(0,"pop_back on empty Blob");
	data->pop_back();
}

#endif

练习16.28

shared_pointer.h

#ifndef SHARED_POINTER_H
#define SHARED_POINTER_H

#include "DebugDelete.h"
#include 

template class shared_pointer;

template void swap(shared_pointer& lhs, shared_pointer& rhs);

template 
class shared_pointer
{
		friend void swap(shared_pointer& lhs, shared_pointer& rhs);
	public:

		shared_pointer() = default;

		explicit shared_pointer(T* up, std::function d = DebugDelete()) :
			ptr(up), refCount(new std::size_t(1)), deleter(d) { }

		shared_pointer(const shared_pointer& sp):
			ptr(sp.ptr), refCount(sp.refCount), deleter(sp.deleter)
		{
			++*refCount;
		}

		//! move constructor
		shared_pointer(shared_pointer&& sp) noexcept;

		//! copy assignment
		shared_pointer& operator =(const shared_pointer& rhs);

		//! move assignment
		shared_pointer& operator =(shared_pointer&& rhs) noexcept;

		//! conversion operator
		operator bool() const
		{
			return ptr ? true : false;
		}

		//! dereference
		T& operator* () const
		{
			return *ptr;
		}

		//! arrow
		T* operator->() const
		{
			return & this->operator *();
		}

		//! return useCount
		std::size_t use_count() const
		{
			return *refCount;
		}

		//! get the underlying pointer
		T* get() const noexcept
		{
			return ptr;
		}

		//! check if the unique user
		bool unique() const noexcept
		{
			return *refCount == 1;
		}

		//! swap
		void swap( shared_pointer& rhs)
		{
			::swap(*this, rhs);
		}

		//! if unique user, free the object pointed to
		void reset() noexcept { decrement_n_destroy(); }

		//! make prt point where p pointing and create a new coount for it
		void reset(T* p)
		{
			if(ptr != p)
			{
				decrement_n_destroy();
				ptr = p;
				refCount = new std::size_t(1);
			}
		}

		//! reset to point where p is pointing and change deleter to d.
		void reset(T *p, const std::function& d)
		{
			reset(p);
			deleter = d;
		}

		//! destructor
		~shared_pointer()
		{
			decrement_n_destroy();
		}
	private:

		//! data structure
		T* ptr = nullptr;
		std::size_t* refCount = new std::size_t(0);

		std::function deleter {DebugDelete()};
		void decrement_n_destroy();

};

template 
inline void
swap(shared_pointer& lhs, shared_pointer& rhs)
{
	using std::swap;
	swap(lhs.ptr, rhs.ptr);
	swap(lhs.refCount, rhs.refCount);
	swap(lhs.deleter, rhs.deleter);
}

//! move constructor
template
inline
shared_pointer::shared_pointer(shared_pointer&& sp) noexcept:
ptr(sp.ptr), refCount(sp.refCount), deleter(std::move(sp.deleter))
{
	sp.ptr = nullptr;
	sp.refCount = nullptr;
}

//! copy assignment
template
inline shared_pointer&
shared_pointer::operator =(const shared_pointer& rhs)
{
	++*rhs.refCount;
	decrement_n_destroy();
	ptr = rhs.ptr;
	refCount = rhs.refCount;
	deleter  = rhs.deleter;

	return *this;
}

//! move assignment
template
inline shared_pointer&
shared_pointer::operator =(shared_pointer&& rhs) noexcept
{
	decrement_n_destroy();
	::swap(*this, rhs);

	std::cout << "shared_pointer::move=\n";

	return *this;
}

template 
inline std::ostream&
operator <<(std::ostream& os, shared_pointer p)
{
	os << p.get();
	return os;
}

template 
inline void
shared_pointer::decrement_n_destroy()
{
	if(ptr)
	{
		if (--*refCount == 0)
		{
			delete refCount;
			deleter(ptr);
		}
		refCount = nullptr;
		ptr = nullptr;
	}
}

#endif

unique_pointer.h

#ifndef UNIQUE_POINTER_H
#define UNIQUE_POINTER_H

#include "DebugDelete.h"

template class unique_pointer;
template void
swap(unique_pointer& lhs, unique_pointer& rhs);

template 
class unique_pointer
{
		friend void swap(unique_pointer& lhs, unique_pointer& rhs);

	public:
		unique_pointer(const unique_pointer&) = delete;
		unique_pointer& operator = (const unique_pointer&) = delete;

		unique_pointer() = default;
		explicit unique_pointer(T* up): ptr(up) { }

		//! move constructor
		unique_pointer(unique_pointer&& up) noexcept
	:
		ptr(up.ptr)
		{
			up.ptr = nullptr;
		}

		//! move assignment
		unique_pointer& operator =(unique_pointer&& rhs) noexcept;

		//! std::nullptr_t assignment
		unique_pointer& operator =(std::nullptr_t n) noexcept;

		//! operator overloaded :  *  ->  bool
		T& operator  *() const
		{
			return *ptr;
		}
		T* operator ->() const
		{
			return & this->operator *();
		}
		operator bool() const
		{
			return ptr ? true : false;
		}

		//! return the underlying pointer
		T* get() const noexcept
		{
			return ptr;
		}

		//! swap member using swap friend
		void swap(unique_pointer &rhs)
		{
			::swap(*this, rhs);
		}

		//! free and make it point to nullptr or to p's pointee.
		void reset()     noexcept { deleter(ptr); ptr = nullptr; }
		void reset(T* p) noexcept { deleter(ptr); ptr = p;       }

		//! return ptr and make ptr point to nullptr.
		T* release();


		~unique_pointer()
		{
			deleter(ptr);
		}
	private:
		T* ptr = nullptr;
		D  deleter = D();
};

//! swap
template
inline void
swap(unique_pointer& lhs, unique_pointer& rhs)
{
	using std::swap;
	swap(lhs.ptr, rhs.ptr);
	swap(lhs.deleter, rhs.deleter);
}

//! move assignment
template
inline unique_pointer&
unique_pointer::operator =(unique_pointer&& rhs) noexcept
{
	if(this->ptr != rhs.ptr)
	{
		deleter(ptr);
		ptr = nullptr;
		::swap(*this, rhs);
	}
	return *this;
}

//! std::nullptr_t assignment
template
inline unique_pointer&
unique_pointer::operator =(std::nullptr_t n) noexcept
{
	if(n == nullptr)
	{
		deleter(ptr);
		ptr = nullptr;
	}
	return *this;
}

template
inline T*
unique_pointer::release()
{
	T* ret = ptr;
	ptr = nullptr;
	return ret;
}
#endif

练习16.39

#include 


template 
int compare(const T &v1, const T &v2)
{
	if (v1 < v2) return -1;
	if (v2 < v1) return 1;
	return 0;
}

int main()
{
	std::cout << compare("sss","aaa") << "\n";
}

练习16.41

template auto sum(T lhs, T rhs) -> decltype( lhs + rhs)
{
    return lhs + rhs;
}

练习16.47

#include 
#include 

void func_lvalue(std::string& lhs, std::string& rhs)
{
    lhs = "Wang\n";
    rhs = "Alan\n";
}

void func_rvalue(int&& lhs, int&& rhs)
{
    //! allocate enough space
    std::allocator alloc;
    int* data(alloc.allocate(3));

    //! move into the spaced newly allocated
    alloc.construct(data    , lhs);
    alloc.construct(data +1 , 0);
    alloc.construct(data +2 , rhs);

    //! print
    for (auto p = data; p != data + 3;  ++p)
        std::cout << *p << "\n";

    //! destroy and deallocation
    for (auto p = data +3; p != data;    )
        alloc.destroy(--p);
    alloc.deallocate(data,3);
}

template
void flip(F f, T1&& t1, T2&& t2)
{
    f(std::forward(t2), std::forward(t1));
}

int main()
{
    //! test for lvalue reference
    /*
    std::string s1, s2;
    flip(func_lvalue, s1, s2);
    std::cout << s1 << s2;
    */

    //! test for rvalue reference
    flip(func_rvalue, 99,88);


}

练习16.51 & 16.52

#include 

template
void foo(T t,Args ...args)
{
	std::cout << sizeof...(Args) << std::endl;
	std::cout << sizeof...(args) << std::endl;
}


int main()
{
	foo(1,2);
	foo(1,23,4,5,6);
}

练习16.53 & 16.54 & 16.55

#include 

class Foo
{};

template
std::ostream& print(std::ostream& os, const T& t)
{
	return os << t;
}


template
std::ostream&
print(std::ostream &os, const T &t, const Args&... rest)
{
	//! print the first argument
	os << t << ",";

	//! recursive call; print the other arguments
	return print(os,rest...);
}


int main()
{
	//print(std::cout, 1);

	print(std::cout, 1,2);

	//print(std::cout, 1,2,3,4,"sss");

	//print(std::cout,foo,bar);

}

练习16.56 & 16.57 

#include 
#include 
#include 


template  std::string debug_rep(const T& t);
template  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 std::string debug_rep(const T& t)
{
	std::ostringstream ret;
	ret << t;
	return ret.str();
}

template std::string debug_rep(T* p)
{
	std::ostringstream ret;
	ret << "pointer: " << p;

	if(p)
		ret << " " << debug_rep(*p);
	else
		ret << " null pointer";

	return ret.str();
}

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
std::ostream& print(std::ostream& os, const T& t)
{
	return os << t;
}

template
std::ostream&
print(std::ostream &os, const T &t, const Args&... rest)
{
	os << t << ",";

	return print(os,rest...);
}

template
std::ostream& errorMsg(std::ostream& os, const Args... rest)
{
	return print(os,debug_rep(rest)...);
}

int main()
{
	errorMsg(std::cout, 1,2,3,4,9.0f,"sss","alan");
}

练习16.61

#include 
#include 

template 
std::shared_ptr wy_make_shared(Args&&...);

int main()
{
	auto p = wy_make_shared(42);
	std::cout << *p  << std::endl;

	auto p2= wy_make_shared(10,'c');
	std::cout << *p2  << std::endl;

}

template 
inline std::shared_ptr
wy_make_shared(Args&&... args)
{
	std::shared_ptr ret( new T(std::forward(args)...));
	return ret;
}

练习16.63 & 16.64

#include 
#include 
#include 

template
std::size_t count(const std::vector& vec, T value);

template<>
std::size_t count (const std::vector &vec, const char* value);

int main()
{
	//ex16.63
	/*
	    std::vector vi = {1,2,3,4,5,6,7,1,1,1,1};
	    std::vector vd = {1.1,1.1,2.3,4};
	    std::cout << count(vd, 1.1);
	*/
	//ex16.64
	std::vector vcc = {"alan","alan","alan","alan","moophy"};
	std::cout << count(vcc, "alan");

	return 0;
}


template
std::size_t count(const std::vector& vec, T value)
{
	std::size_t count = 0;
	for(auto& item : vec)
		count += (item == value)? 1 : 0 ;

	return count;
}

template<>
std::size_t count (const std::vector &vec, const char* value)
{
	std::size_t count = 0;
	for(auto& item : vec)
		count += (strcmp(item,value) == 0)? 1 : 0;

	return count;
}

你可能感兴趣的:(《C++primer(第五版)》学习之路-第十六章:模板与泛型编程)