[笔记]《Effective C++》第七章 Templates and Generic Programming
C++ template机制自身是一部完整的图灵机(Turing-complete):它可以被用来计算任何可计算的值。
条款41:Understand implicit interfaces and compile-time polymorphism.
- classes和templates都支持接口(interfaces)和多态(polymorphism)。
- 对classes而言接口是显式的(explicit),以函数签名为中心。多态则是通过virtual函数发生于运行期。
- 对template参数而言,接口是隐式的(implicit),奠基于有效表达式。多态则是通过template具现化和函数重载解析(function overloading resolution)发生于编译期。
- 在OOP(面向对象编程)中,总是以显式接口(explicit interfaces)和运行期多态(runtime polymorphism)解决问题。
- 在Templates及泛型编程中,显式接口和运行期多态仍然存在,但重要性降低。反倒是隐式接口(implicit interfaces)和编译期多态(compile-time polymorphism)移到前头了。
- “以不同的template参数具现化function templates”会导致调用不同的函数,这便是所谓的编译期多态(compile-timepolymorphism)。
- 通常显式接口由函数的签名式(也就是函数名称、参数类型、返回类型)构成。
class Widget{
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
};
- 隐式接口并不基于函数签名式,而是由有效表达式(valid expressions)组成。
template<typename T>
void doProcessing(T& w)
{
if(w.size() > 10 && w != someNastyWidget)
{
T temp(w);
temp.normalize();
temp.swap(w);
}
}
- 加诸于template参数身上的隐式接口,就像加诸于class对象身上的显式接口一样真实,而且两者都在编译期完成检查。
条款42:Understand the two meanings of typename.
- 声明template参数时,前缀关键字class和typename可互换。
- 请使用关键字typename标识嵌套从属类型名称;但不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。
- template内出现的名称如果相依于某个template参数,称之为从属名称(dependent names)。如果从属名称在 class 内呈嵌套状,我们称它为嵌套从属名称(nested dependent name)。
- C++有个规则可以解析(resolve)此一歧义状态:如果解析器在template中遭遇一个嵌套从属名称,它便假设这名称不是个类型,除非你告诉它是。
- 任何时候当你想要在template中指涉一个嵌套从属类型名称,就必须在紧临它的前一个位置放上关键字 typename。
条款43:Know how to access names in templatized base classes.
我们必须有某种办法令C++“不进入templatized base classes观察”的行为失效。
- 第一是在base class函数调用动作之前加上"this->":
template< typename Company>
class LoggingMsgSender : public MsgSender<Company> {
public:
...
void sendClearMsg(const MsgInfo& info)
{
//将“传送前”的信息写至log;
this->sendClear(info); //成立,假设sendClear将被继承。
//将“传送后”的信息写至log;
}
...
};
- 第二是使用using声明式。
template< typename Company>
class LoggingMsgSender : public MsgSender<Company> {
public:
using MsgSender<Company>::sendClear; //告诉编译器,请它假设sendClear位于base class内。
...
void sendClearMsg(const MsgInfo& info)
{
...
sendClear(info); //成立,假设sendClear将被继承。
...
}
...
};
- 第三个做法是,明白指出被调用的函数位于baseclass内。但这往往是最不让人满意的一个解法,因为如果被调用的是virtual函数,上述的明确资格修饰(explicit qualification)会关闭“virtual绑定行为”。
template< typename Company>
class LoggingMsgSender : public MsgSender<Company> {
public:
...
void sendClearMsg(const MsgInfo& info)
{
...
MsgSender<Company>::sendClear(info); //成立,假设sendClear将被继承。
...
}
...
};
条款44:Factor parameter-independent code out of templates.
- Templates生成多个classes和多个函数,所以任何template代码都不该与某个造成膨胀的template参数产生相依关系。
- 因非类型模板参数(non-type template parameters)而造成的代码膨胀,往往可消除,做法是以函数参数或class成员变量替换template参数。
- 因类型参数(type parameters)而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述(binary representations)的具现类型(instantiation types)共享实现码。
条款45:Use member function templates to accept"all compatible types."
- 请使用member function templates(成员函数模板)生成“可接受所有兼容类型”的函数。
- 如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符。
- STL容器的迭代器几乎总是智能指针。
条款46:Define non-member functions inside templates when type conversions are desired.
- 当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“class template 内部的friend函数”。
- 在template实参推导过程中从不将隐式类型转换函数纳入考虑。
- template class内的friend声明式可以指涉某个特定函数。
条款47:Use traits classes for information about types.
- Traits classes使得“类型相关信息”在编译期可用。它们以templates和“templates特化”完成实现。
- 整合重载技术(overloading)后,traits classes有可能在编译期对类型执行if...else测试。
- STL迭代器分类:
- Input迭代器:只能向前移动,一次一步,客户只可读取(不能涂写)它们所指的东西,而且只能读取一次。
- Output迭代器:只能向前移动,一次一步,客户只可涂写它们所指的东西,而且只能涂写一次。
- forward迭代器:可以做前述两种分类所能做的每一件事,而且可以读或写其所指物一次以上。
- Bidirectional迭代器:除了可以向前移动,还可以向后移动。
- random access迭代器:可以在常量时间内向前或向后跳跃任意距离。
- 所有forward迭代器都是input迭代器,依此类推。
- 如何设计并实现一个traits class:
- 确认若干你希望将来可取得的类型相关信息。
- 为该信息选择一个名称(例如iterator_category)。
- 提供一个template和一组特化版本,内含你希望支持的类型相关信息。
- 如何使用一个traits class:
- 建立一组重载函数(身份像劳工)或函数模板,彼此间的差异只在于各自的traits参数。令每个函数实现码与其接受之traits信息相应和。
- 建立一个控制函数(身份像工头)或函数模板,它调用上述那些“劳工函数”并传递traits class所提供的信息。
条款48:Be aware of template metaprogramming.
- Template metaprogramming(TMP,模板元编程)是编写template-based C++程序并执行于编译期的过程。
- 所谓template metaprogram(模板元程序)是以C++写成、执行于C++编译器内的程序。一旦TMP程序结束执行,其输出,也就是从templates具现出来的若干C++源码,便会一如往常地被编译。
- TMP的优缺点:
- 让某些事情更容易。
- 可将工作从运行期转移到编译期。某些错误原本通常在运行期才能侦测到,现在可在编译期找出来。
- 更高效:较小的可执行文件、较短的运行期、较少的内存需求。
- 编译时间变长。
分类:
读书笔记
标签:
Note
, Effective C++
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!