Namespaces
Variants

Class template

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Class template
Function template
Miscellaneous

类模板定义了一族类。

目录

语法

template < parameter-list > class-declaration (1)
template < parameter-list > requires constraint class-declaration (2) (自 C++20 起)
export template < parameter-list > class-declaration (3) (于 C++11 移除)

说明

class-declaration - 一个 类声明 。声明的类名成为模板名称。
parameter-list - 非空的逗号分隔 模板形参 列表,其中每个形参可以是 常量形参 类型形参 模板形参 ,或这些类型的任意 形参包
constraint - 一个 约束表达式 ,用于限制此类模板接受的模板形参
export 曾是一个可选修饰符,用于将模板声明为 已导出 (当用于类模板时,会同时声明其所有成员为已导出)。实例化已导出模板的文件无需包含其定义:仅声明即可。实际实现 export 功能的编译器较为罕见,且在细节实现上存在分歧。 (直至 C++11)

类模板实例化

类模板本身不是类型、对象或任何其他实体。仅包含模板定义的源文件不会生成任何代码。为了产生实际代码,模板必须被实例化:必须提供模板参数,以便编译器能够生成实际的类(或从函数模板生成函数)。

显式实例化

template 类关键字 模板名 < 参数列表 > ; (1)
extern template 类关键字 模板名 < 参数列表 > ; (2) (C++11 起)
类关键字 - class , struct union
1) 显式实例化定义
2) 显式实例化声明

显式实例化定义强制实例化其所引用的类、结构体或联合体。它可以出现在模板定义之后的程序任意位置,并且对于给定的 实参列表 ,在整个程序中仅允许出现一次,不要求诊断信息。

显式实例化声明(extern template)会跳过隐式实例化步骤:原本会导致隐式实例化的代码将改用其他地方提供的显式实例化定义(如果不存在这样的实例化则会导致链接错误)。这可用于减少编译时间,方法是在所有使用该模板的源文件中显式声明模板实例化(仅保留一个文件除外),并在剩余文件中显式定义它。

(since C++11)

类、函数 、变量 (since C++14) 以及成员模板特化都可以从其模板进行显式实例化。类模板的成员函数、成员类以及静态数据成员可以从其成员定义进行显式实例化。

显式实例化只能出现在模板的封闭命名空间中,除非使用限定标识符:

namespace N
{
    template<class T>
    class Y // 模板定义
    {
        void mf() {}
    };
}
// template class Y<int>; // 错误:类模板 Y 在全局命名空间中不可见
using N::Y;
// template class Y<int>; // 错误:显式实例化位于模板所属命名空间之外
                          // 的命名空间
template class N::Y<char*>;       // 正确:显式实例化
template void N::Y<double>::mf(); // 正确:显式实例化

如果先前已经为同一组模板参数出现了 显式特化 ,则显式实例化不会产生任何效果。

仅当显式实例化函数模板 、变量模板 (C++14 起) 、类模板的成员函数或静态数据成员,或成员函数模板时,要求其声明可见。对于类模板、类模板的成员类或成员类模板的显式实例化,必须在实例化前出现完整定义,除非先前已出现具有相同模板参数的显式特化。

如果函数模板 、变量模板 (since C++14) 、成员函数模板,或类模板的成员函数或静态数据成员通过显式实例化定义进行显式实例化,则模板定义必须存在于同一翻译单元中。

当显式实例化指名一个类模板特化时,它相当于对其中每个未被先前在翻译单元中显式特化的非继承非模板成员进行同类型(声明或定义)的显式实例化。若此显式实例化为定义,则仅对此时已定义的成员同时构成显式实例化定义。

显式实例化定义会忽略成员访问说明符:参数类型和返回值类型可能是私有的。

隐式实例化

当代码在需要完全定义类型的上下文中引用模板,或者当类型的完整性影响代码,且该特定类型尚未显式实例化时,就会发生隐式实例化。例如,在构造该类型的对象时会发生隐式实例化,但在构造指向该类型的指针时则不会发生。

这适用于类模板的成员:除非该成员在程序中被使用,否则它不会被实例化,也不需要定义。

template<class T>
struct Z // 模板定义
{
    void f() {}
    void g(); // 从未定义
};
template struct Z<double>; // Z<double> 的显式实例化
Z<int> a;                  // Z<int> 的隐式实例化
Z<char>* p;                // 此处未实例化任何内容
p->f(); // 在此处发生 Z<char> 和 Z<char>::f() 的隐式实例化
        // Z<char>::g() 始终未被需要且从未实例化:
        // 无需定义该函数

如果在实例化点处类模板已被声明但未定义,则该实例化将产生不完整类类型:

template<class T>
class X;    // 声明,非定义
X<char> ch; // 错误:不完整类型 X<char>
局部类 及其成员中使用的任何模板,都会随着声明该局部类或枚举的实体的实例化而一同实例化。 (C++17 起)

关键词

export (C++11前) extern (C++11起)

参见