【 声明:版权所有,转载请标明出处,请勿用于商业用途。 联系信箱:[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;
}
#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;
}
#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;
}
#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;
}
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
#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;
}
#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;
}
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
#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
#ifndef WY_TEXTQUERY_H
#define WY_TEXTQUERY_H
#include
#include
#include
#include
#include
#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;
}
#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
#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 [" <
#include
#include
#include
#include "DebugDelete.h"
#include
#include "wy_queryresult.h"
#include "wy_textquery.h"
int main()
{
return 0;
}
#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
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
#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";
}
template auto sum(T lhs, T rhs) -> decltype( lhs + rhs)
{
return lhs + rhs;
}
#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);
}
#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);
}
#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);
}
#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");
}
#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;
}
#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;
}