1 模板
(1) 类/函数 模板 区别
否/是有 `模板实参推断`
使用时 是/否必须 `explicitly 指定 模板实参`
Queue<int> queue;
compare(1, 0); // 不用 compare<int>(1, 0)
(2) 模板形参
1] 类型形参
2] 非类型形参
template <typename T, size_t N>
#include <iostream>
template <typename T, size_t N>
void array_init( T (&parm) [N] )
{ //(1) func template 的 `para 是 数组的引用
for( size_t i = 0; i < N; ++i)
parm[i] = i;
}
int main()
{
int arr[5];
//(2) 函数调用 时, compiler `从 数组实参 计算 非类型形参 的值`
// instantiate array_init( int (&) [5] )
array_init(arr);
}
2 实例化
模板实参推导
(1) `受限转换`
1) const 转换
1) func template 的 para 是 `non-reference type` 时,
para/arg type 都
`const ignored`
2) `array / function type` 转换为 `pointer`
3) template para 的 type 被 推导出 后,
`不再 implicitly converted`
3 template 编译模型
(1) inclusion 编译模型
[1] 头文件 要 #include 4 种 定义
1] func template
2] class template 的
1> 非模板 mem func
2> 模板 mem func
3] class 的
模板 mem func
[2] 问题: 多 源文件 use 同一 template 时, 其 `同一实例 可能 实例化多次`
compiler 是否优化, 要查 compiler 用户指南
// 1. utilities.h
template <class T>
int compare(const T&, const T&);
#include "utilities.cpp"
// 2. utilities.cpp
template <typename T>
int compare(const T& x, const T& y)
{
if (x < y)
return -1;
if (y < x)
return 1;
return 0;
}
[3] separate 编译模型: `不通用`
4 类模板成员
[1] class template scope 内,
用 class name 时, 可 不用指定 template para
[2] 类模板 外 定义 mem func 时
必须
1) 以 template 开头, 后接 template para list
2) class name 包含 template para
template <class T>
return_type Queue<T>::member_name
[3] class template 的 mem 非模板函数 是 template
与 非成员 的 模板函数 区别
1} 实例化 时, `不进行 模板实参 推导`
=> 允许 arg 的 type conversion
`template para 由 定义 class template 的 obj 的 template arg 确定`
2] `更灵活`
// void push(const T& val)
// => 2) instantiates Queue<int>::push(const int&)
// => 3) short 型 arg s converted to int 型 and passed to push
short s = 1;
q1.push(s);
[4] 成员模板
用途
泛化 copy ctor / assignment
Queue<short> -> Queue<int>
mem template 类外定义 时,
`必须含 2个 template para list`
template <class T> template <class Iter>
void Queue<T>::assign(Iter beg, Iter end) { /* ... */ }
[5] template para 一 一 映射: (有时才有意义)
QueueItem<T> 的 友元 唯一对应 Queue<T>,
template <class T>
class QueueItem
{
friend class Queue<T>;
//...
}
5 泛型 句柄类
将 `RC` 和 继承层次中 `基础 obj 的 ptr 管理` 泛型化
image.png
image.png
将 `concrete Handle 拆成 2 层
generic Handle class
余下 `中介层 class ( 如 名为 ) Handle_client`
dtor 调用链
`~Handle_client() -> 调 ~Handle()-> 调 deRC(): *RC 减完后 == 0 时, delete ptr -> 调 ptr 所指 实际类型 的 dtor`
// === 1
template <class T>
class Handle
{
private:
T* ptr;
size_t* pRC;
void deRC()
{
if (-- * pRC == 0)
{
delete ptr;
delete pRC;
}
}
public:
Handle(T* p = 0) :
ptr(p), pRC(new size_t(1)) {}
Handle(const Handle& rhs) :
ptr(rhs.ptr), pRC(rhs.pRC) { ++* pRC; }
Handle& operator=(const Handle&);
~Handle() { deRC(); }
T& operator*();
T* operator->();
const T& operator*() const;
const T* operator->() const;
};
template <class T>
inline Handle<T>&
Handle<T>::operator=(const Handle& rhs)
{
++* rhs.pRC;
deRC();
ptr = rhs.ptr;
pRC = rhs.pRC;
return *this;
}
template <class T>
inline T&
Handle<T>::operator*()
{
if (ptr)
return *ptr;
throw std::runtime_error("dereference of unbound Handle");
}
template <class T>
inline const T&
Handle<T>::operator*() const
{
if (ptr)
return *ptr;
throw std::runtime_error("...");
}
template <class T>
inline T*
Handle<T>::operator->()
{
if (ptr)
return ptr;
throw std::runtime_error("access through unbound Handle");
}
template <class T>
inline const T*
Handle<T>::operator->() const
{
if (ptr)
return ptr;
throw std::runtime_error("...");
}
// === 2
class Handle_client
{
private:
Handle<Base> handle;
public:
Handle_client() : handle() {}
Handle_client(const Base& rB):
handle(rB.clone()) {}
// Handle_client(const Handle_client& rhs) { handle = rhs.handle; }
// Handle_client& operator=(const Handle_client& rhs) { handle = rhs.handle; return *this;}
// ~Handle_client() { handle.~Handle(); }
//(4) * ->: forward (转发) work to Handle class
const Base& operator*() const { return *handle; }
const Base* operator->() const { return handle.operator->(); }
};
void test()
{
Base b = Base("book1", 20);
Derived d = Derived("book2", 30);
Handle_client hc1(b);
Handle_client hc2(d);
{
Handle_client hc3 = hc1;
Handle_client hc4 = hc2;
}
hc1 = hc2;
}
after `Handle_client hc4 = hc2` result:
image.png
image.png
6 防止 自身赋值
assignment 为什么要 防止 `自身赋值`?
|
|/
若 `释放 旧资源` => 引发问题
|
|
因 赋给新值 时, 要 use 旧资源
例: String 的 internal ptr + 赋值运算中 不检查自我赋值, 直接 delete [] p;
class String {
public:
String& operator=(const String& rhs);
private:
char *p; // new str[];
};
String& String::operator=(const String& rhs)
{
// not check self assignmemt
//1) delete old memory
delete [] p;
//2) allocate new memory
p = new char[strlen(rhs.p) + 1];
//3) copy resource pointed to by rhs's pointer mem
strcpy(p, rhs.p);
return *this;
}
7 模板 特化 / specialization
(1) 意义
对某些类型
泛化版
1] `错误`
2] 实例化 `效率低`
// 泛化版 对 T = const char* 错误
template <typename T>
int compare(const T& v1, const T& v2)
{
if (v1 < v2)
return -1;
if (v2 < v1)
return 1;
return 0
}
(2) function template 特化
形式
[1] template 后接 空尖括号 <>
[2] template name 后 <> 中 指定 特化版 template paras
T = const char* 时,
const T& (const reference) + const char* (指向 const 的 ptr) = const char* const&
// eg2. solution of eg1
template <>
int
compare<const char*>(const char* const& v1,
const char* const& v2)
{
return strcmp(v1, v2);
}
(3) class template 特化?有几种,各有什么区别
default, copy C 风格 字符串 只会 copy ptr
若 `ptr 指向 动态内存, 往往需要 特化版`
[1] 全特化 + 外部 定义 mem 时` -> `不用 template<>
// 泛化
template <class T>
class Queue
{
public:
void push(const T&);
};
template <>
class Queue<const char*>
{
public:
void push(const char*);
};
void Queue<const char*>::push(const char* p_val)
{
return real_queue.push(p_val);
}
[2] 只特化 class template 的 `部分 mem` -> 用 template<>
template <>
void Queue<const char*>::push(const char* const& p_val)
{
char* p_new = new char[ strlen(p_val) + 1 ];
strncpy(p_new, p_val, strlen(p_val) + 1 );
QueueItem<const char*>* pt =
new QueueItem<const char*>(p_new);
if (empty())
head = tail = pt;
else
{
tail->tail = pt;
tail = pt;
}
}
template <>
void Queue<const char*>::pop()
{
QueueItem<const char*>* pt = head;
delete head->item;
head = head->next;
delete pt;
}
[3] 只 特化 class template 的 部分 template para: 偏特化
template <class T1, class T2>
class A
{
};
// partial specialization: fix T2 as int
template<class T1>
class A<class T1, int>
{
};
网友评论