1 C++ template 机制的 发展
[1] 建立 type-safe 的 容器
vector 等
[2] GP code 与其所处理的对象 独立
algorithm: for_each / find 等
[3] 是 图灵机
可用于计算 任何可计算的值
[4] TMP
编译时计算
1 implicit interface
和 编译期 多态
1 OO
相对于 `模板参数 T` 上的 `运算符重载` 而言 的 explicit, 而不是 相对于 编译期 implicit 生成的 explicit
|\
| 含义
|
总是以 `explicit interface` + `运行期多态` 解决问题
|
|/
explicit public interface
= implicit public interface ( compiler 隐含生成 )
+ explicit 声明的 public interface
void f(A& a)
{
if( a.size() > 0 && a != someNastyWidget )
/* ... */
}
2 GP
与 OO 不同
`implicit interface 和 编译期多态` 更重要
|
| explicit interface 和 运行期多态 仍存在, 但 重要性 降低
|
| 分析
|/
`从 function 到 function template 时 发生什么`
template <typename T>
void f(T& t)
{
if( t.size() > 0 && t != someNastyWidget )
/* ... */
}
(1) `object 必须支持的 interface`
由 template 中 `加诸于 object` 身上的 `操作` 决定
|
|/
`implicict interface`
|
| 即
|/
`模板参数 T 的 implicit interface 约束`
————————————————————————————————————————————————————
[1] 表面约束 | 不必满足
————————————————————————————————————————————————————
[2] 真正约束 | 包含了 `运算符 重载` 带来的可能性
————————————————————————————————————————————————————
[1] 表面约束: 不必满足
1] T 必须 `提供 成员函数 size()`
return 整数
2] T 必须 `支持 operator!= 运算符重载`
[2] 真正约束: overloaded function 下
1] T 必须 `支持 成员函数 size()`
但可 `从 base class 继承` 而来
2] size() 不必 return 整数
return 类型 X
|
|/
有 成员 比较运算符 operator> (Y, int)
X 可转换为 Y
3] T 不必支持 operator !=
operator!= (X, Y)
T / someNastyWIdget 可 implicitly 转换为 X / Y
Note
未考虑 逻辑与运算符重载 operator &&
(2) 凡 `涉及 object` 的任何 `function call`
可能造成 `template 实例化` 以 使 函数调用 success
|
|
|/
编译期 `多态`
|
|/
`不同 模板参数 T`
3 compile-time / runtime polymorphism
————————————————————————————————————————————————————————
编译期 哪个 overloaded function `该 (还没)` 被 `调用`
————————————————————————————————————————————————————————
运行期 哪个 vf` 该 被 `绑定`
————————————————————————————————————————————————————————
4 `explicit interface / implicit interface: 均在 compile-time 完成 检查`
(1) 加诸于 `class` 身上的 explicit interface
(2) 加诸于 `模板参数 T` 身上的 implicit interface
5 remember
OO vs. GP
都支持 interface 和 polymorphism
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
interface | 多态机制
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
[1] class | explicit + function signature | vf -> 运行时多态
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
[2] template | implicit + 运算符重载 | template 实例化 + 重载解析 ( overloading resolution ) -> 编译期多态
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
2 typename 双重含义
1 typename 双重含义
[1] `模板参数 声明式` 中, typename
|
|
等价 class
[2] `明确告诉 compiler` `嵌套依赖 名称` 是 `type` 名
的 一种方法
2 template 内可 `refer to` 2 种 名称`
`依赖 / 非依赖 名称`
(1) 非依赖 名称
(2) `依赖` 名称 -> `嵌套 依赖` 名称 -> `嵌套 依赖 类型` 名称
——————————————————————————————————————————————————————————————
依赖 | `依赖于 模板参数 T`
——————————————————————————————————————————————————————————————
嵌套 | `作用域 限定符` 限定 // 如 `C::const_iterator`
——————————————————————————————————————————————————————————————
`C++ template 解析`
compiler 默认 `嵌套依赖名称` 为 `non-type`
除非 `明确告诉 compiler` `嵌套依赖 名称` 是 `type` 名
————————————————————————————————————————————————————————————————
[1] typename
————————————————————————————————————————————————————————————————
[2] 放 `base class list 或 mem init. list`
————————————————————————————————————————————————————————————————
3 typename 之 `别名`
3 访问 模板基类
内 名称
1 需求
编译期 `据 Info` 决定 `哪个 Info` pass 到 `哪家 Company ( 模板参数 T )`
————————————————————————————————————————
代码组织
————————————————————————————————————————
[1] 1种 模板实参
[2] 模板基类
[3] 模板派生类: public 继承 `模板基类`
template<typename T>
void D<T>::sendExplicitMsg(const Info& info)
{
// send 前 log
sendExplicit(info); // 欲 调 Base<T> 的 public interface func: sendExplicit(info)
// send 后 log
}
————————————————————————————————————————
2 问题
`C++ compiler 不进` 入 `模板化的 base class` 查找
=> 遇 `模板派生类 D<T>` 定义 时
compiler `无法知道 模板基类 B<T>` 的 `实例化版本` 长什么样
=> 无法知道 它 `有没有 其 主模板 的 interface func`
Note
`全特化版 与 主模板 interface 可能不同`
|
| 可能
|/
没有 主模板 中 某 `interface func`
3 解决
但不一定为真
|\
|
对 compiler `承诺 模板基类`
`特化版 都支持 泛化版` 所提供的 `interface`
=> compiler `未遇 interface 调用` 时, `先让 编译通过`
`遇 interface 调用`
+ `相应 特化版(class) 不支持 interface`
=> `编译报错`
D<T2> d; // B<T2> 内没 sendExplicitMsg(...)
Info info;
// ...
d.sendExplicitMsg(info); // 编译 error
3种方法
————————————————————————————————————————————————————————————————————————————————————————
(1) this-> | this->sendExplicit(info);
————————————————————————————————————————————————————————————————————————————————————————
(2) using 声明 | using B<T>::sendExplicit + sendExplicit(info)
————————————————————————————————————————————————————————————————————————————————————————
(3) Base class template 名限定 | B<T>::sendExplicit(info);
————————————————————————————————————————————————————————————————————————————————————————
4 抽出 与 模板参数 T 无关
的 code
1 共性与变性分析
(1) 2 个 function -> 共同部分 搬到 新 function -> 原 2 function 调 新 function
(2) `2 个 class -> 共同部分 -> 新 class -> inheritance / composition`
(3) `template 中, 重复 太隐晦`
————————————————————————————————————————————————
重复
interface func `依赖于 2个模板参数 T+N`
client 给定 2对 模板实参
=> 2 个 实例化版本
[1] Matrix<double, 3>::invert()
[2] Matrix<double, 5>::invert()
————————————————————————————————————————————————
|
| 去重
|/
————————————————————————————————————————————————————————————————
`继承 + 转调` 将
依赖于 `2个模板参数`
|
| 转换为
|/
只依赖一个 `模板参数 T` + 另一 `模板参数 N 替换为 para`
令 interface func
template <typename T, std::size_t N>
void Derived::invert() { this->invert(N); }
转调
template <typename T>
Base::invert(size_t n)
——————————————————————————————————————————————————————————————————
2 `从某个角度看, 一些代码重复 反倒有利`
(1) base 存 protected pointer 指向 数据
`封装性 降低`
(2) base 存 ptr 指向 数据 -> 可能 动态或静态 内存分配
`ptr 该不该 delete ?`
3 某些 mem func 操作 T* -> 调 另一 func 操作 void* -> 完成实际工作
5 用 成员(函数)模板
接受 all 兼容 types
1 `native pointer 与 smart pointer`
`native pointer` 支持 `隐式转换`
Derived* -> Base*
ptr to non-const-> ptrto const
SP: SP<Top> 与 SP<Mid> 是 完全不同的 class
=> SP 默认 `无隐式转换`
|
| 2 `SP 想 实现 隐式转换`
|/
用 `成员 ( 函数 ) 模板`
如: 泛化 copy ctor: SP<U> -> SP<T>
蓄意 non-explicit => `让 SP 支持 隐式转换`
template<typename T>
class SP{
public:
template<typename U> // mem template
SP(const SP<U>& rhs);
};
| `int* 到 doule* 的 隐式转换 被 编译器拒绝`
|
| 也不希望 SP<int> 到 SP<sp> 的 隐式转换
|/
3 SP `约束 转换`
[1] 思想
SP 的 internal ptr 能 隐式转换时, 才允许 SP 隐式转换
[2] 方法
利用 rhs.get() 取出 internal ptr
rhs 的 inernal ptr `初始化` lhs 的 inernal ptr `就是 限制`
template<typename T>
template<typename U>
SP::SP(const SP<U>& rhs)
: ptr(rhs.get() ) { /* ... */ }
4 mem template 用于 assignment
shared_ptr copy/assignment 的 para 可为
————————————————
[1] shared_ptr
[2] auto_ptr
[3] weak_ptr
————————————————
6 需 类型转换
时, 在 template 内定义 非成员函数: friend 函数(模板)
part4-7 的 泛化
1 `类 / 非成员函数 -> 泛化`
[1] `模板(函数) 实参推导` 可能失败 template<typename T>
const Rational<T>
整型 -> 类类型 // 2 -> Rational<T> operator*(const Rational<T>& lhs, const Rational<T>& rhs) {
| return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator() );
| 解决 }
|
| Rational<int> oneHalf(1, 2);
|/ Rational<int> result = oneHalf * 2; // 编译 error
[2] 非模板
2 -> Rational 可 隐式转换
2 解决
friend 作用 `不是 访问` class 的 `non-public 部分`
|\
| 这里
|
`模板类` 内 `定义 friend 函数(模板)`
模板类 `实例化` 的同时
friend 函数(模板) 被 `自动 实例化` 为 函数
|
| `整型 作 实参 调 类的 Ctor`
|/
整型 到 类类型 的 隐式转换 // 2 -> Rational<T>
(1) 模板类 `内 声明` friend
模板类 外定义 friend
`链接失败`
(2) 解决1: 模板类 `内 定义` friend
(3) 解决2
为 支持 `inline`
令 `模板类 内 friend 函数(模板)` 定义式
调 `模板类 外 helper 函数模板`
|
| 若必要
|/
头文件内 定义 helper template
3 `模板类 内 模板名` 可作 `模板名 + 模板参数` 的 `简化式`
|
|/
Rational == Rational<T>
7 用 traits
class 表现 type infomation
1 5种 迭代器
[1] 空 struct: 只起 tag 作用
[2] `除 输出迭代器 外`, 从 `输入迭代器` 开始, `逐层 继承`
——————————————————————————————————————————
InputIter
只读
istream_iterator
——————————————————————————————————————————
OutputIter
只写
ostream_iterator
——————————————————————————————————————————
ForwardIter
读写
单向链表 slist: 非标准
——————————————————————————————————————————
BiIter
双向
list set map multiset multimap
——————————————————————————————————————————
RAIter
随机
vector deque string
——————————————————————————————————————————
2 advance 表现
移动 迭代器
template<typename Iter, typename D>
void advance(Iter& iter, D d);
观念上 只是做 iter += d
实际要用 traits
3 traits class
习惯上 总是实现为 struct
(1) traits 是 `1 种技术`
用于 `萃取 type` 的 `某种信息`
| |
|/ |/
iterator category
(2) traits 要 `同时支持 built-in / user-defined 类型`
泛化 / 特化 template
(3) traits `设计`
[1] 确定 对 目标 type
`要 萃取 什么信息`
[2] 为 `次信息` 选 `nane`
| |
| |
|/ |/
category iterator_category
[3] `template 泛化 + 特化 版`
template<typename Iter>
struct iterator_traits
{
typedef typename
Iter::iterator_category iterator_category;
};
template<typename Iter>
struct iterator_traits<Iter*> // 偏特化: 针对 native pointer
{
typedef
random_access_iterator_tag iterator_category;
};
(4) `用户自定义 iterator 类型`, 必须 `内嵌 次信息 的 别名`
|
|/
iterator_category
(5) 实现 advance
思路
`traits` 引发 `编译期` 发生于 type 身上的 `条件计算/判断`
=> 不能用 if-else 语句 + typeid, 因为
`if 语句 运行期 才执行`
实现
[1] `重载 function ( template ) 组`
差异只在于 `traits 参数`
[2] `traits class 所 `萃取 信息` 的 `临时对象` 作 实参 `调 重载 function`
|
|/
`只用于 实参推导` 之 `类型匹配`
|
compiler `重载解析` 调 适当 `重载版本` | => 不需要 name
| |
|/ |
随机/双向/输入 |
|
template<typename Iter, typename D> |
void advance(Iter& iter, D d) |
{ |
doAdvance(iter, d, |
typename |/
std::iterator_traits<Iter>::iterator_category()
);
}
template<typename Iter, typename D>
void doAdvance(Iter& iter, D d,
std::random_access_iterator_tag)
{
iter += d;
}
8 TMP
模板元编程
1 TMP
(1) `编译期 计算`-> 输出: `template 实例化 code`
`再` 正常 `编译`
(2) 利弊
——————————————————————————————————————————————
利
——————————————————————————————————————————
[1] `错误检测` 从 运行期 `提前` 到 编译期
——————————————————————————————————————————
[2] 高效
——————————————————————————————————
1] 可执行文件 小
2] 运行期 短
3] 内存 小
——————————————————————————————————————————————
弊
编译时间变长
——————————————————————————————————————————————
2 traits 解法是1种 TMP
3 advance 的 if...else + typeid 解法` 的 `编译期问题`
随机迭代器 版本
|\
|
`不使用的版本`, compiler 也会 `生成 code`
|
|/
却 `无法保证 编译通过`
虽然是 运行期执行
=== 详细
1 implicit interface
和 编译期 多态
2 typename 双重含义
1 typename 双重含义
[1] `模板参数 声明式` 中, typename
|
|
等价 class
[2] `明确告诉 compiler` `嵌套依赖 名称` 是 `type` 名
的 一种方法
2 template 内可 `refer to` 2 种 名称`
`依赖 / 非依赖 名称`
(1) 非依赖 名称
(2) `依赖` 名称 -> `嵌套 依赖` 名称 -> `嵌套 依赖 类型` 名称
——————————————————————————————————————————————————————————————
依赖 | `依赖于 模板参数 T`
——————————————————————————————————————————————————————————————
嵌套 | `作用域 限定符` 限定 // 如 `C::const_iterator`
——————————————————————————————————————————————————————————————
`C++ template 解析`
compiler 默认 `嵌套依赖名称` 为 `non-type`
除非 `明确告诉 compiler` `嵌套依赖 名称` 是 `type` 名
————————————————————————————————————————————————————————————————
[1] typename
————————————————————————————————————————————————————————————————
[2] 放 `base class list 或 mem init. list`
————————————————————————————————————————————————————————————————
[1]
// error
template<typename C>
void f(const C& container, // C 非 嵌套 name
C::const_iterator* iter); // C::const_iterator 嵌套 name
// ok
template<typename C>
void f(const C& container,
typename C::const_iterator* iter);
[2]
template<typename T>
class Derived: public Base<T>::Nested // 1] base class list 中 不允许 typename
{
public:
explicit Derived(int x)
: Base<T>::Nested(x) // 2] mem init. list 中 不允许 typename
{
typename Base<T>::Nested temp; // else: 需 typename
}
};
3 typename 之 `别名`
std:iterator_traits<Iter>::value_type 是 Iter 所指对象的 type
Iter 是 std::list<string>::iterator => value_type 是 string
template<typename Iter>
void f(Iter iter)
{
typedef typename std:iterator_traits<Iter>::value_type value_type;
value_type temp(*iter);
}
3 访问 模板基类
内 名称
1 需求
编译期 `据 Info` 决定 `哪个 Info` pass 到 `哪家 Company ( 模板参数 T )`
// [1] 1种 模板实参
class T1
{
public:
void send(const std::string& msg);
};
// [2] 模板基类
template<typename T>
class B
{
public:
void sendExplicit(const Info& info) // class Info { /* ... */ };
{
std::string msg;
// 据 info -> msg
T t;
t.send(msg);
}
};
// [3] 模板派生类: public 继承 `模板基类`
template<typename T>
class D: public B<T>
{
public:
void sendExplicitMsg(const Info& info)
{
// send 前 log
sendExplicit(info); // 欲 调 Base<T> 的 public interface func: sendExplicit(info)
// send 后 log
}
// ...
};
2 问题
`C++ compiler 不进` 入 `模板化的 base class` 查找
=> 遇 `模板派生类 D<T>` 定义 时
compiler `无法知道 模板基类 B<T>` 的 `实例化版本` 长什么样
=> 无法知道 它 `有没有 其 主模板 的 interface func`
Note
`全特化版 与 主模板 interface 可能不同`
|
| 可能
|/
没有 主模板 中 某 `interface func`
template<>
class B<T2>
{
public:
// 无 sendExplicit()
};
3 解决
但不一定为真
|\
|
对 compiler `承诺 模板基类`
`特化版 都支持 泛化版` 所提供的 `interface`
=> compiler `未遇 interface 调用` 时, `先让 编译通过`
`遇 interface 调用`
+ `相应 特化版(class) 不支持 interface`
=> `编译报错`
D<T2> d; // B<T2> 内没 sendExplicitMsg(...)
Info info;
// ...
d.sendExplicitMsg(info); // 编译 error
3种方法
————————————————————————————————————————————————————————————————————————————————————————
(1) this-> | this->sendExplicit(info);
————————————————————————————————————————————————————————————————————————————————————————
(2) using 声明 | using B<T>::sendExplicit + sendExplicit(info)
————————————————————————————————————————————————————————————————————————————————————————
(3) Base class template 名限定 | B<T>::sendExplicit(info);
————————————————————————————————————————————————————————————————————————————————————————
4 抽出 与 模板参数 T 无关
的 code
class template 的 mem func `使用时 才 实例化`
1 共性与变性分析
(1) 2 个 function -> 共同部分 搬到 新 function -> 原 2 function 调 新 function
(2) `2 个 class -> 共同部分 -> 新 class -> inheritance / composition`
(3) `template 中, 重复 太隐晦`
————————————————————————————————————————————————
重复
interface func `依赖于 2个模板参数 T+N`
client 给定 2对 模板实参
=> 2 个 实例化版本
[1] Matrix<double, 3>::invert()
[2] Matrix<double, 5>::invert()
————————————————————————————————————————————————
|
| 去重
|/
————————————————————————————————————————————————————————————————
`继承 + 转调` 将
依赖于 `2个模板参数`
|
| 转换为
|/
只依赖一个 `模板参数 T` + 另一 `模板参数 N 替换为 para`
令 interface func
template <typename T, std::size_t N>
void Derived::invert() { this->invert(N); }
转调
template <typename T>
Base::invert(size_t n)
——————————————————————————————————————————————————————————————————
template <typename T, std::size_t N>
class Matrix
{
public:
void invert(); // 求逆
};
Matrix<double, 3> m1;
// ...
m1.invert();
Matrix<double, 5> m2;
// ...
m2.invert();
|
| 去重
|/
template <typename T>
class MatrixBase
{
protected:
MatrixBase(std::size_t n, T* p)
: size(n), ptr(p) {}
void invert(std::size_t n);
private:
std::size_t size;
T* ptr;
};
template <typename T,
std::size_t N>
class Matrix
{
public:
Matrix()
: MatrixBase<T>(N, data) {}
void invert()
{
this->invert(N); // [3] 告诉 compiler Base 的 所有版本 都支持 public func invert(...)
}
private:
T data[N*N]; // [2] 也可以 动态内存分配
using MatrixBase<T>::invert; // [1] 避免 hide base 的 mem func
};
2 `从某个角度看, 一些代码重复 反倒有利`
(1) base 存 protected pointer 指向 数据
`封装性 降低`
(2) base 存 ptr 指向 数据 -> 可能 动态或静态 内存分配
如何判断 `ptr 是否该 delete ?`
3 某些 mem func 操作 T* -> 调 另一 func 操作 void* -> 完成实际工作
5 用 成员(函数)模板
接受 all 兼容 types
1 `native pointer 与 smart pointer`
`native pointer` 支持 `隐式转换`
Derived* -> Base*
ptr to non-const-> ptrto const
SP: SP<Top> 与 SP<Mid> 是 完全不同的 class
=> SP 默认 `无隐式转换`
|
| 2 `SP 想 实现 隐式转换`
|/
用 `成员 ( 函数 ) 模板`
如: 泛化 copy ctor: SP<U> -> SP<T>
蓄意 non-explicit => `让 SP 支持 隐式转换`
template<typename T>
class SP{
public:
template<typename U> // mem template
SP(const SP<U>& rhs);
};
| `int* 到 doule* 的 隐式转换 被 编译器拒绝`
|
| 也不希望 SP<int> 到 SP<sp> 的 隐式转换
|/
3 SP `约束 转换`
[1] 思想
SP 的 internal ptr 能 隐式转换时, 才允许 SP 隐式转换
[2] 方法
利用 rhs.get() 取出 internal ptr
rhs 的 inernal ptr `初始化` lhs 的 inernal ptr `就是 限制`
template<typename T>
template<typename U>
SP::SP(const SP<U>& rhs)
: ptr(rhs.get() ) { /* ... */ }
template<typename T>
class SP
{
public:
template<typename U>
SP(const SP<U>& rhs)
: ptr(rhs.get() ) { /* ... */ }
T* get() const { return ptr; }
private:
T* ptr;
};
4 mem template 用于 assignment
shared_ptr copy/assignment 的 para 可为
————————————————
[1] shared_ptr
[2] auto_ptr
[3] weak_ptr
————————————————
template<typename T>
class shared_ptr
{
public:
template<typename U>
explicit shared_ptr(U* p);
// [1] copy ctor
shared_ptr(shared_ptr const& sp);
template<typename U> // 泛化 copy ctor: 支持 隐式转换
shared_ptr(shared_ptr<U> const& sp);
template<typename U>
explicit shared_ptr(weak_ptr<U> const& sp);
template<typename U>
explicit shared_ptr(auto_ptr<U> const& sp);
// [2] assignment
shared_ptr&
operator=(shared_ptr const& sp); // assignment
template<typename U> // 泛化 asignment
shared_ptr&
operator=(shared_ptr<U> const& sp);
template<typename U>
shared_ptr&
operator=(auto_ptr<U> const& sp);
};
6 需 类型转换
时, 在 template 内定义 非成员函数: friend 函数(模板)
part4-7 的 泛化
1 `类 / 非成员函数 -> 泛化`
[1] `模板(函数) 实参推导` 可能失败
整型 -> 类类型 // 2 -> Rational<T>
|
| 解决
|/
[2] 非模板
2 -> Rational 可 隐式转换
template<typename T>
class Rational
{
public:
Rational (const T& numerator = 0, const T& denominator = 1);
const T& numerator() const;
const T& denominator() const;
};
template<typename T>
const Rational<T>
operator*(const Rational<T>& lhs, const Rational<T>& rhs) {
return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator() );
}
Rational<int> oneHalf(1, 2);
Rational<int> result = oneHalf * 2; // 编译 error
2 解决
friend 作用 `不是 访问` class 的 `non-public 部分`
|\
| 这里
|
`模板类` 内 `定义 friend 函数(模板)`
模板类 `实例化` 的同时
friend 函数(模板) 被 `自动 实例化` 为 函数
|
| `整型 作 实参 调 类的 Ctor`
|/
整型 到 类类型 的 隐式转换 // 2 -> Rational<T>
(1) 模板类 `内 声明` friend
模板类 外定义 friend
`链接失败`
template<typename T>
class Rational
{
friend // [1] 声明
const Rational operator*(const Rational& lhs, const Rational& rhs);
public:
/* 同前 */
};
// [2] 定义
template<typename T>
const Rational<T>
Rational::operator*(const Rational<T>& lhs, const Rational<T>& rhs) { /* 同前 */ }
(2) 解决1: 模板类 `内 定义` friend
template<typename T>
class Rational
{
friend // class template 内 定义 friend function template
const Rational
operator*(const Rational& lhs,
const Rational& rhs)
{
// ...
}
public:
// ... // 同前
};
(3) 解决2
为 支持 `inline`
令 `模板类 内 friend 函数(模板)` 定义式
调 `模板类 外 helper 函数模板`
|
| 若必要
|/
头文件内 定义 helper template
template<typename T>
class Rational;
// [2]
template<typename T>
const Rational<T>
doMultiply(const Rational<T>& lhs, const Rational<T>& rhs);
template<typename T>
class Rational
{
friend // [1] 令 `模板类 内 friend 函数(模板)` 调 `模板类 外 helper 函数模板`
const Rational
operator*(const Rational& lhs, const Rational& rhs) {
return doMultiply(lhs, rhs);
}
public:
// ...
};
// [3] 若必要, 头文件内 定义 helper template
template<typename T>
const Rational<T>
doMultiply(const Rational<T>& lhs,
const Rational<T>& rhs)
{
return Rational<T>(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator() );
}
Note
就本例而言, 这种方法意义不大, 但对 复杂函数,却意义很大
3 `模板类 内 模板名` 可作 `模板名 + 模板参数` 的 `简化式`
|
|/
Rational == Rational<T>
template<typename T>
class Rational
{
friend
const Rational<T>
operator*(const Rational<T>& lhs, const Rational<T>& rhs);
public:
/* 同前 */
};
<=>
template<typename T>
class Rational
{
friend // 声明
const Rational
operator*(const Rational& lhs, const Rational& rhs);
public:
/* 同前 */
};
7 用 traits
class 表现 type infomation
1 5种 迭代器
Input iterator
只读
istream_iterator
Output iterator
只写
ostream_iterator
forward iterator
读写
非 STL 的 程序库中 单向链表 slist
Bidirectional iterator
双向
list set map multiset multimap
random access iterator
随机
vector deque string
// tag struct
struct
input_iterator_tag {};
struct
output_iterator_tag {};
struct
forward_iterator_tag: public input_iterator_tag {};
struct
bidirectional_iterator_tag: public forward_iterator_tag {};
struct
random_access_iterator_tag: public bidirectional_iterator_tag {};
2 advance 表现
移动 迭代器
template<typename Iter, typename D>
void advance(Iter& iter, D d);
观念上 只是做 iter += d
实际要用 traits
3 traits class
习惯上 总是实现为 struct
(1) traits 是 `1 种技术`
用于 `萃取 type` 的 `某种信息`
| |
|/ |/
iterator category
(2) traits 要 `同时支持 built-in / user-defined 类型`
泛化 / 特化 template
(3) traits `设计`
[1] 确定 对 目标 type
`要 萃取 什么信息`
[2] 为 `次信息` 选 `nane`
| |
| |
|/ |/
category iterator_category
[3] `template 泛化 + 特化 版`
template<typename Iter>
struct iterator_traits
{
typedef typename
Iter::iterator_category iterator_category;
};
template<typename Iter>
struct iterator_traits<Iter*> // 偏特化: 针对 native pointer
{
typedef
random_access_iterator_tag iterator_category;
};
(4) `用户自定义 iterator 类型`, 必须 `内嵌 次信息 的 别名`
|
|/
iterator_category
template<...>
class list
{
public:
class iterator
{
public:
typedef
bidirectional_iterator_tag iterator_category;
};
};
(5) 实现 advance
思路
`traits` 引发 `编译期` 发生于 type 身上的 `条件计算/判断`
=> 不能用 if-else 语句 + typeid, 因为
`if 语句 运行期 才执行`
实现
[1] `重载 function ( template ) 组`
差异只在于 `traits 参数`
[2] `traits class 所 `萃取 信息` 的 `临时对象` 作 参数 `调 重载 function`
|
|/
`只用于 实参推导` 之 `类型匹配`
|
compiler `重载解析` 调 适当 `重载版本` |
| |
|/ |
随机/双向/输入 |
|
template<typename Iter, typename D> |
void advance(Iter& iter, D d) |
{ |
doAdvance(iter, d, |
typename |/
std::iterator_traits<Iter>::iterator_category()
);
}
template<typename Iter, typename D>
void doAdvance(Iter& iter, D d,
std::random_access_iterator_tag) // 第 3 para 不需要 name
{
iter += d;
}
template<typename Iter, typename D>
void doAdvance(Iter& iter, D d,
std::bidirectional_iterator_tag )
{
if( d > 0)
{
while (d--)
++iter;
}
else
{
while (d++)
--iter;
}
}
template<typename Iter, typename D>
void doAdvance(Iter& iter, D d,
std::input_iterator_tag )
{
if( d < 0)
throw std::out_of_range(" - distance ");
while(d--)
++iter;
}
8 TMP
模板元编程
1 TMP
(1) `编译期 计算`-> 输出: `template 实例化 code`
`再` 正常 `编译`
(2) 利弊
——————————————————————————————————————————————
利
——————————————————————————————————————————
[1] `错误检测` 从 运行期 `提前` 到 编译期
——————————————————————————————————————————
[2] 高效
——————————————————————————————————
1] 可执行文件 小
2] 运行期 短
3] 内存 小
——————————————————————————————————————————————
弊
编译时间变长
——————————————————————————————————————————————
2 traits 解法是1种 TMP
3 advance 的 if...else + typeid 解法` 的 `编译期问题`
随机迭代器 版本
|\
|
`不使用的版本`, compiler 也会 `生成 code`
|
|/
却 `无法保证 编译通过`
虽然是 运行期执行
template<typename Iter, typename D>
void advance(Iter& iter, D d)
{
if( typeid( typename std::iterator_traits<Iter>::iterator_category )
== typeid( std::random_access_iterator_tag ) )
{
iter += d;
}
else
{
else
{
if( d > 0) { while (d--) ++iter; }
else { while (d++) --iter; }
}
}
}
std::list<int>::iterator iter;
// ...
advance(iter, 10);
// 实例化版本
void advance(std::list<int>::iterator& iter, int d)
{
if( typeid( std::iterator_traits< std::list<int>::iterator >::iterator_category )
== typeid( std::random_access_iterator_tag ) )
{
iter += d; // 编译不过
}
else
{
if( d > 0) { while (d--) ++iter; }
else { while (d++) --iter; }
}
}
网友评论