类模板
类模板定义了一系列类。
内容 |
[编辑] 语法
template < parameter-list > class-declaration |
(1) | ||||||||
template < parameter-list > requires constraint class-declaration |
(2) | (since C++20) | |||||||
export template < parameter-list > class-declaration |
(3) | (removed in C++11) | |||||||
[编辑] 解释
class-declaration | - | 一个 类声明。声明的类名成为模板名。 |
parameter-list | - | 一个非空的逗号分隔的 模板形参 列表,每个形参可以是 非类型形参、类型形参、模板形参,或者这些形参的形参包。 |
constraint | - | 一个约束表达式,它限制了此模板类接受的模板形参 |
export 是一个可选的修饰符,用于将模板声明为导出的(当与类模板一起使用时,它声明其所有成员也都是导出的)。实例化导出模板的文件不需要包含它们的定义:声明就足够了。 export 的实现很少见,并且在细节上存在分歧。 |
(until C++11) |
[编辑] 类模板实例化
类模板本身不是类型、对象或任何其他实体。不会从仅包含模板定义的源文件生成任何代码。为了使任何代码出现,必须实例化模板:必须提供模板实参,以便编译器可以生成实际的类(或来自函数模板的函数)。
[编辑] 显式实例化
template class-key template-name < argument-list > ; |
(1) | ||||||||
extern template class-key template-name < argument-list > ; |
(2) | (since C++11) | |||||||
class-key | - | class 、struct 或 union |
显式实例化定义强制实例化它们引用的类、结构体或联合体。它可以出现在程序中模板定义之后的任何位置,并且对于给定的 argument-list,在整个程序中只允许出现一次,不需要诊断。
显式实例化声明(extern 模板)跳过隐式实例化步骤:否则会导致隐式实例化的代码改为使用别处提供的显式实例化定义(如果不存在此类实例化,则导致链接错误)。这可以通过在除一个源文件外的所有源文件中显式声明模板实例化,并在其余文件中显式定义它来减少编译时间。 |
(since C++11) |
类、函数、变量(since C++14)和成员模板特化可以从它们的模板中显式实例化。类模板的成员函数、成员类和静态数据成员可以从它们的成员定义中显式实例化。
显式实例化只能出现在模板的封闭命名空间中,除非它使用 qualified-id
namespace N { template<class T> class Y // template definition { void mf() {} }; } // template class Y<int>; // error: class template Y not visible in the global namespace using N::Y; // template class Y<int>; // error: explicit instantiation outside // of the namespace of the template template class N::Y<char*>; // OK: explicit instantiation template void N::Y<double>::mf(); // OK: explicit instantiation
如果之前为同一组模板实参出现了显式特化,则显式实例化无效。
当显式实例化函数模板、变量模板(since C++14)、类模板的成员函数或静态数据成员或成员函数模板时,只需要声明可见。完整的定义必须出现在类模板、类模板的成员类或成员类模板的显式实例化之前,除非之前出现了具有相同模板实参的显式特化。
如果函数模板、变量模板(since C++14)、成员函数模板或类模板的成员函数或静态数据成员通过显式实例化定义进行显式实例化,则模板定义必须存在于同一翻译单元中。
当显式实例化命名类模板特化时,它充当翻译单元中尚未预先显式特化的每个非继承的非模板成员的相同种类(声明或定义)的显式实例化。如果此显式实例化是定义,则它也仅对于此时已定义的成员才是显式实例化定义。
显式实例化定义忽略成员访问说明符:形参类型和返回类型可能是私有的。
[编辑] 隐式实例化
当代码在需要完全定义的类型的上下文中引用模板,或者当类型的完整性影响代码时,并且此特定类型尚未显式实例化,则会发生隐式实例化。例如,当构造此类型的对象时,而不是当构造指向此类型的指针时。
这适用于类模板的成员:除非在程序中使用该成员,否则不会实例化该成员,并且不需要定义。
template<class T> struct Z // template definition { void f() {} void g(); // never defined }; template struct Z<double>; // explicit instantiation of Z<double> Z<int> a; // implicit instantiation of Z<int> Z<char>* p; // nothing is instantiated here p->f(); // implicit instantiation of Z<char> and Z<char>::f() occurs here. // Z<char>::g() is never needed and never instantiated: // it does not have to be defined
如果在实例化点声明了类模板,但未定义,则实例化会产生不完整的类类型
template<class T> class X; // declaration, not definition X<char> ch; // error: incomplete type X<char>
局部类及其成员中使用的任何模板都作为声明局部类或枚举的实体的实例化的一部分进行实例化。 | (since C++17) |
[编辑] 关键字
export(until C++11)extern(since C++11)