1. 程式人生 > >《C++primer(第五版)》學習之路-第十六章:模板與泛型程式設計

《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 <iostream>
#include <vector>
#include <list>
#include <string>


template<typename iteratorT, typename valueT>
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<int> 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<std::string> l = {"aa","bb","cc","dd","ee","ff","gg"};
	std::list<std::string>::const_iterator itL = find(l.cbegin(), l.cend(), "ee");
	std::cout << *itL << std::endl;

	return 0;
}

練習16.5
#include <iostream>
#include <string>

template<typename Arr>
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 <iostream>
#include <vector>
#include <list>
#include <string>

template<typename T, unsigned size>
T* begin(const T(&arr)[size])
{
	return arr;
}

template<typename T, unsigned size>
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 <iostream>
#include <vector>
#include <list>
#include <string>

template<typename T, unsigned size>
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 <memory>

template<typename T>
class Vec
{
	public:
		Vec():element(nullptr), first_free(nullptr), cap(nullptr) { }
		Vec(std::initializer_list<T> 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<T> 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<T*, T*> alloc_n_copy(T* b, T* e);
};


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


//! constructor that takes initializer_list<T>
template<typename T>
Vec<T>::Vec(std::initializer_list<T> 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<typename T>
Vec<T>& Vec<T>::operator =(const Vec& rhs)
{
	//! allocate and copy first to protect against self_assignment
	std::pair<T*,T*> 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<typename T>
Vec<T>::~Vec()
{
	free();
}

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

template<typename T>
void Vec<T>::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<typename T>
void Vec<T>::resize(std::size_t n)
{
	resize(n, T());
}

template<typename T>
void Vec<T>::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<typename T>
std::pair<T*,T*>
Vec<T>::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<typename T>
void Vec<T>::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<typename T>
void Vec<T>::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<typename T>
void Vec<T>::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 <vector>
#include <iostream>

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

	Vec<int> 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 <iostream>
#include <vector>
#include <list>

//! ex16.19 using size() to control the loop
template<typename Container>
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<typename Container>
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<int> v = {1,23,6,4,5,7,4};
	std::list<std::string> 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 <iostream>

class DebugDelete
{
	public:
		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;
};
#endif

StrBlob.h
#ifndef STRBLOB_H
#define STRBLOB_H

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <stdexcept>

class StrBlobPtr;

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

		StrBlob() : data(std::make_shared<std::vector<std::string>>()) { }
		StrBlob(std::initializer_list<std::string> 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<std::vector<std::string>> data;
		void check(size_type i, const std::string &msg) const;
};

inline StrBlob::StrBlob(std::initializer_list<std::string> il):	data(std::make_shared<std::vector<std::string>>(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<std::vector<std::string>> check(std::size_t, const std::string&) const;

		std::weak_ptr<std::vector<std::string>> 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<std::vector<std::string>>
                                       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 <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <memory>

class wy_queryResult;

class wy_textQuery
{
	public:
		typedef std::shared_ptr<std::vector<std::string>> sp_file_Tp;
		typedef std::shared_ptr<std::map<std::string,std::set<int>>> 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 <sstream>
#include <algorithm>

wy_textQuery::wy_textQuery(std::ifstream &fin) :
	sp_fileData(new std::vector<std::string>(), DebugDelete() ),
	sp_queryMap(new std::map<std::string, std::set<int>>(), 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 [" <<queryWord <<"] occurs " <<qr.getCounter() <<" times :\n";

	auto sp_m = qr.getSp_Qmap();
	auto sp_f = qr.getSp_file();

	for(const auto &index : (*sp_m)[queryWord])
		std::cout << "\n(Line " <<index <<") " << (*sp_f)[index] << "\n\n";
}

main.cpp
#include <iostream>
#include <vector>
#include <list>

#include "DebugDelete.h"
#include <memory>

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

int main()
{
	return 0;
}

練習16.24
#ifndef BLOB_H
#define BLOB_H
#include <memory>
#include <vector>

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

		Blob();
		Blob(std::initializer_list<T> il);

		template<typename It>
		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<std::vector<T>> data;
		void check(size_type i, const std::string &msg) const;
};

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>
template<typename It>
Blob<T>::Blob(It b, It e) :
	data(std::make_shared<std::vector<T>>(b,e))
{}

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>
const T& Blob<T>::back() const
{
	check(0,"back on empty Blob");
	return data->back();
}


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


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

template<typename T>
void Blob<T>::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 <functional>

template<typename> class shared_pointer;

template<typename T> void swap(shared_pointer<T>& lhs, shared_pointer<T>& rhs);

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

		shared_pointer() = default;

		explicit shared_pointer(T* up, std::function<void(T*)> 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<void(T*)>& 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<void(T*)> deleter {DebugDelete()};
		void decrement_n_destroy();

};

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

//! move constructor
template<typename T>
inline
shared_pointer<T>::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<typename T>
inline shared_pointer<T>&
shared_pointer<T>::operator =(const shared_pointer& rhs)
{
	++*rhs.refCount;
	decrement_n_destroy();
	ptr = rhs.ptr;
	refCount = rhs.refCount;
	deleter  = rhs.deleter;

	return *this;
}

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

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

	return *this;
}

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

template <typename T>
inline void
shared_pointer<T>::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<typename, typename> class unique_pointer;
template<typename T,typename D> void
swap(unique_pointer<T,D>& lhs, unique_pointer<T,D>& rhs);

template <typename T, typename D = DebugDelete>
class unique_pointer
{
		friend void swap<T,D>(unique_pointer<T,D>& lhs, unique_pointer<T,D>& 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<T, D> &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<typename T, typename D>
inline void
swap(unique_pointer<T,D>& lhs, unique_pointer<T,D>& rhs)
{
	using std::swap;
	swap(lhs.ptr, rhs.ptr);
	swap(lhs.deleter, rhs.deleter);
}

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

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

template<typename T, typename D>
inline T*
unique_pointer<T,D>::release()
{
	T* ret = ptr;
	ptr = nullptr;
	return ret;
}
#endif

練習16.39

#include <iostream>


template <typename T>
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<std::string>("sss","aaa") << "\n";
}

練習16.41
template<typename T> auto sum(T lhs, T rhs) -> decltype( lhs + rhs)
{
    return lhs + rhs;
}

練習16.47
#include <iostream>
#include <memory>

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<int> 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<typename F, typename T1, typename T2>
void flip(F f, T1&& t1, T2&& t2)
{
    f(std::forward<T2>(t2), std::forward<T1>(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 <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()
{
	foo(1,2);
	foo(1,23,4,5,6);
}

練習16.53 & 16.54 & 16.55
#include <iostream>

class Foo
{};

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&... 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 <iostream>
#include <memory>
#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& t)
{
	std::ostringstream ret;
	ret << t;
	return ret.str();
}

template<typename T> 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<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&... rest)
{
	os << t << ",";

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

template<typename... Args>
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 <iostream>
#include <memory>

template <typename T, typename ... Args>
std::shared_ptr<T> wy_make_shared(Args&&...);

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

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

}

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

練習16.63 & 16.64
#include <iostream>
#include <vector>
#include <cstring>

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

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

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

	return 0;
}


template<typename T>
std::size_t count(const std::vector<T>& 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<const char*> &vec, const char* value)
{
	std::size_t count = 0;
	for(auto& item : vec)
		count += (strcmp(item,value) == 0)? 1 : 0;

	return count;
}

相關推薦

C++primer()》學習-模板程式設計

【宣告:版權所有,轉載請標明出處,請勿用於商業用途。聯絡信箱:[email protected]】 16.1 定義模板 1.模板定義以關鍵字template開始,後跟一個模板引數列表,這是一個逗號分隔的一個或多個模板引數的列表,用小於號(<)和大於號(&

c primer plus()編程練習-編程練習

兩個感嘆號 nal getchar putc 進制 類型 運算 pre 重做 1.編寫一個程序。該程序讀取輸入直到遇到#字符,然後報告讀取的空格數目、讀取的換行符數目以及讀取的所有其他字符數目。 #include<stdio.h> #include<ct

c primer plus()編程練習-編程練習

main tdi blog plus prim span int 統計 rime 1.設計一個程序,統計從輸入到文件結尾為止的字符數。 #include<stdio.h> int main(void){ int ch; int i; i

Python小白學習)—【內置函數一】

tro item 求和 整數 Coding rop 數學運算 memory 保留 將68個內置函數按照其功能分為了10類,分別是: 數學運算(7個) abs()   divmod()   max()    min()   pow()   round()   

Python小白學習)—【內建函式一】

將68個內建函式按照其功能分為了10類,分別是: 數學運算(7個) abs()    divmod()    max()    min()    pow()    round()    sum() 型別

opengl學習,SSAO

Note 本節暫未進行完全的重寫,錯誤可能會很多。如果可能的話,請對照原文進行閱讀。如果有報告本節的錯誤,將會延遲至重寫之後進行處理。 我們已經在前面的基礎教程中簡單介紹到了這部分內容:環境光照(Ambient Lighting)。環境光照是我們加入場景總體光

Linux 學習一)壓縮歸檔以及RAID

壓縮、解壓縮命令 壓縮格式:gz,bz2,xz,zip,Z 壓縮演算法不同,壓縮比(壓縮後的大小-壓縮前的大小/壓縮前的大小)可能也會不同。 compress:FILENAME.Z uncompress 只能壓縮檔案,預設會刪除原檔案保留壓縮後文件: gzip

Linux 學習一)RAID和LVM

傳輸速度 Mb/8=MB 硬碟的介面: IDE(ATA):133Mbps 並行匯流排 SATA:300Mbps,600Mbps,6Gbps 序列匯流排 USB:USB3.0:480Mbps 序列匯流排 SCSI:Small Computer System Int

java學習——第二

  BasicWeb 基礎知識:          HTML          CSS   

12.29--C++模板程式設計--《C++ Primer學習

今天學習第16章《模板與泛型程式設計》 感覺腦子有點模模糊糊的,效率不是很高,趕快寫一下學習日誌備忘。 模板其實在java中用的也多了,但是C++的沒用過,感覺有點虛。 其實的確是差不多的用法,所以記幾個點好了。 1. 模板形參表,即template <typename

OpenCV探索圖像矯正技術深入探討

double gb2 教科書 長方形 strong fine open lines 導致 剛進入實驗室導師就交給我一個任務,就是讓我設計算法給圖像進行矯正。哎呀,我不太會圖像這塊啊,不過還是接下來了,硬著頭皮開幹吧! 那什麽是圖像的矯正呢?舉個例子就好明白了。 我的好朋友小

C++ primer 模板程式設計

繼續瀏覽c++ primer 看到模板與泛型程式設計這章,就順便把這幾節的程式碼綜合了下,對一個Queue佇列模板的實現 貼一下程式碼(看完書,自己敲,忘記了哪再看下書) #include <ostream> using std::ostream; //宣告Q

模板程式設計(二)--《C++ primer

 通常在呼叫普通函式時,我們只要做到將函式的宣告放到其定義的前面,保證編譯器先掌握到函式的宣告,因此我們會把其函式宣告放到標頭檔案,而其定義放到原始檔當中;但是模板不同,為了生成一個例項化版本,編譯器需要掌握函式模板或類模板成員函式的定義,所以模板標頭檔案通常既包括宣告

“全棧2019”Java繼承欄位

難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 IntelliJ IDEA v2018.3 文章原文連結 “全棧2019”Java第四十六章:繼承與欄位 下一章 “全棧2019”Java第四十七章:繼承與方法 學習小組

effective C++筆記--模板程式設計(三)

文章目錄 請使用traits classes表現型別資訊 認識模板超程式設計 請使用traits classes表現型別資訊 . traits並不是C++的關鍵字或是預先定義好的構件,它們是一種技術,也是一個C++程式設計師共同遵守的協議

effective C++筆記--模板程式設計(二)

文章目錄 運用成員函式模板接受所有相容型別 需要型別轉換時請為模板定義非成員函式 運用成員函式模板接受所有相容型別 . 真實指標做的很好的一件事是支援隱式轉換,派生類的指標可以指向基類的指標,指向非常量物件的指標可以指向轉換成常量物件的指

effective C++筆記--模板程式設計(一)

文章目錄 瞭解隱式介面和編譯器多型 瞭解typename的雙重意義 學習處理模板化基類內的名稱 將與引數無關的程式碼抽離template 瞭解隱式介面和編譯器多型 . 面向物件程式設計世界總是以顯式介面和執行期多型解決問題。比

C++面試總結(三)模板程式設計

1.什麼是模板?    泛型程式設計是指獨立與任何型別的方式編寫程式碼。泛型程式設計和麵向物件程式設計,都依賴與某種形式的多型。面向物件程式設計的多型性在執行時應用於存在繼承關係的類,一段程式碼可以可以忽略基類和派生類之間的差異。在泛型程式設計中,編寫的程式碼可以用作多種型別

C/C++基礎--模板程式設計

模板引數 函式模板,編譯器根據實參來為我們推斷模板實參。 模板中可以定義非型別引數,表示一個值而非一個型別,這些值必須是常量表達式,從而允許編譯器在編譯時例項化模板。 非型別引數可以是整型,或者一個指向物件或函式的指標或(左值)引用。繫結到前者的實參必須是常量表達式,繫結到後者的必須具有靜態生存期

《Effective C++》模板程式設計條款32-條款40

條款41:瞭解隱式介面和編譯期多型 class支援顯示介面和執行期多型 class的顯示介面由函式的名籤式構成(函式名稱、引數型別、返回型別) class的多型通過virtual函式發生在執行期 template支援隱式介面和編譯期多型 templa