7.5 模板编译模型
设定了概念(参见7.2节)之后,我们就可以检查模板的实参是否满足其概念。在此过程中发现的错误会被报告给程序员,程序员必须修正问题。还有一些实参在此刻无法进行检查,如非约束模板参数的实参,这些实参的检查会推迟到用给定模板实参为模板生成代码的时候,即“模板实例化时刻”。对于概念产生之前的代码,这个时刻就是进行所有类型检查的时刻。而使用了概念之后,在概念检查成功之后才会进行这一步。
实例化时刻(后)类型检查的一个不好的副作用是类型错误发现得过晚、会产生刺眼的糟糕错误信息,因为编译器只有在组合了来自程序中多个地方的信息后才发现问题。
实例化时刻的模板类型检查会检查模板定义中的实参使用。这提供了常称为鸭子类型(duck typing,“如果它走路像鸭子,叫声像鸭子,那么它就是一只鸭子”)的一个编译时变体。或者用更专业的术语描述,我们对一些值进行操作,那么一个操作的存在和含义仅依赖于其操作的值。这不同于另外一个视角:对象具有类型,类型决定了操作的存在和含义。值是“存活”于对象内的。这是对象(如变量)在C++中的工作方式,而只有满足对象要求的值才能放到对象中。在编译时使用模板所做的事情多半是不涉及对象的,只涉及值。唯一的例外是constexpr函数(参见1.6节)中的局部变量,在编译器中它是作为对象使用的。
为了使用一个非约束模板,其定义(而不仅是其声明)必须在使用位置所在的作用域中。例如,标准库头文件<vector>包含vector的定义。在实践中,这意味着模板定义通常是置于头文件而非.cpp文件中。当我们打算使用模块(参见3.3节)时,这一点有所改变。如果使用模块,对普通函数和模板函数,源代码的组织方式是相同的。对于这两类函数,其定义都会受到保护,免受文本包含带来的问题。 ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access