在声明“std :: vector <x> f();”中,是“std :: vector <x>”实例化吗?</x> </x>

时间:2011-10-11 18:42:26

标签: c++ templates

C ++语言标准规定了标准库中有关模板组件的以下内容:

  

效果未定义...如果在实例化模板组件时将不完整类型用作模板参数,除非特别允许该组件(C ++11§17.6.4.8/ 2)。

以下是否会导致std::vector类模板的实例化?

class X;
std::vector<X> f(); // Declaration only; we will define it when X is complete

另一种方式是,在函数声明std::vector<X> f();中,std::vector是否使用参数X进行实例化?或者,std::vector<X>是否在f()使用或定义之前未实例化?

同样,以下是否会导致std::vector类模板的实例化?

class X;
typedef std::vector<X> XVector; // We will complete X before we use XVector

虽然我在这些示例中使用std::vector,但问题同样适用于所有模板。

2 个答案:

答案 0 :(得分:5)

§14.7.1\ 1隐式实例化[temp.inst]

  

除非已明确表示类模板特化   实例化(14.7.2)或明确专门化(14.7.3),类   模板特化是在隐式实例化的时候   在需要a的上下文中引用特化   完全定义的对象类型或类的完整性   type影响程序的语义。隐式实例化   类模板专门化导致隐式实例化   声明,但不是定义或默认参数,   类成员函数,成员类,静态数据成员和   会员模板;它导致隐式实例化   成员匿名联盟的定义。除非是班级成员   模板或成员模板已显式实例化或   明确专门化,成员的专业化是隐含的   在上下文中引用特化时实例化   要求成员定义存在; 特别是   静态数据的初始化(以及任何相关的副作用)   除非静态数据成员本身在其中使用,否则不会发生成员   一种需要静态数据成员定义的方法。

§8.3.5\ 9函数[dcl.fct]

  

不应在返回或参数类型中定义类型。的类型   函数定义的参数或返回类型不应为   不完整的类类型(可能是cv-qualified)除非函数   definition嵌套在该类的member-specification中   (包括在类中定义的嵌套类中的定义)。

§3.1\ 2声明和定义[basic.def]

  

声明是一个定义,除非声明没有的函数   指定函数的主体(8.4),它包含extern说明符   (7.1.1)或连接规范25(7.5),既不是初始化程序   也不是函数体,它在类中声明了一个静态数据成员   定义(9.4),它是一个类名声明(9.1),它是一个   opaque-enum-declaration(7.2),或者是typedef声明(7.1.3),   一个using-declaration(7.3.3),一个static_assert-declaration(第7条),   属性声明(第7条),空声明(第7条),   或使用指令(7.3.4)。

只有在需要时才会实例化。我无法在任何地方找到明确的定义,但第二句话说这些声明不是定义,对我来说似乎是相同的。

答案 1 :(得分:2)

不,它不会实例化模板。 Mooing Duck的答案提供了所有必要的引用,但这里有一些分析。

默认情况下,如果不存在要求完全定义的类型(第14.7.1 / 1节),则不会发生实例化。函数定义特别需要完整的类型(第8.3.5 / 9节),但问题是标准的其他部分是否也要求其他声明。

但是定义有一个特殊的例外,它揭示了非定义声明确实不同:

  

函数定义的参数类型或返回类型不应是不完整的类类型(可能是cv限定的),除非函数定义嵌套在该类的成员规范中(包括定义的嵌套类中的定义)在课堂内)。

成员规范中的函数定义有什么特别之处?因为成员规范不能两次声明相同的函数(§9.2/ 1),并且在所有成员声明(§3.3.7/ 1.1)之后处理成员函数体。本质上,嵌套的成员函数定义在第一次传递期间被视为声明,然后在处理完整个成员规范之后被定义为一个定义,并且该类已完成(第9.2 / 2节)。并且§8.3.5/ 9规定第一次通过允许不完整的类,但不允许第二次通过。

对标准的函数声明和实例化规则进行详尽,明确的搜索是非常繁琐的。但是这个例子虽然仅限于成员函数和封闭类型的完整性,但可以合理地扩展到其他函数和类型。无论如何,这是一个很好的证据。