《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