模板实际上必须是编译时构造吗?

时间:2011-05-12 14:38:55

标签: c++ templates

C ++标准实际上要求模板是否必须在编译时实例化,而不是在运行时?

如果没有,我们纯粹使用它是一种惯例,因为这样做显然是有意义的吗?或者是否有一些实际的理由在理论上会阻止现有的实现可以在运行时实例化模板?

3 个答案:

答案 0 :(得分:9)

所有标准要求是可观察行为就好像模板在程序开始运行之前被实例化一样。例如,任何错误都必须在编译的某个阶段触发消息,或者至少在运行时之前触发消息。从理论上讲,编译器可能会将完整的实例化推迟到运行时,但实际上,它必须在编译时完成大部分工作,以确保出现任何潜在的错误消息。

从更严格的意义上讲,该标准将“翻译”视为一个单元;一个实现可以,并且实现具有(并且我认为一些仍然存在)将实例化推迟到链接时间。当涉及动态链接时,这会产生有趣的问题。但标准没有提到:动态链接实际上是未定义的行为,就标准而言,因此需要实现。

但是,最终:实例化模板是编译器执行的最昂贵的操作之一,并且需要非常大且复杂的机制。没有供应商想要强制执行可执行文件。所以不管漏洞如何,不要指望很快就能看到编译时实例化。特别是因为它不会为你买任何东西:标准要求所有模板都可以在编译时实例化,所以你不能以某种方式实例化一个模板依赖于运行时参数,仍然是标准的符合。

答案 1 :(得分:7)

您无法在运行时(在运行时)在C ++程序中创建类型;它们在编译时都是已知的。即使动态加载的共享库也不会改变它;库中的类型集在编译时是已知的(编译库时),并且加载程序必须能够处理库公开的类型。

因此,运行时无需进行模板评估;这些信息在编译时都是已知的。

如果要在运行时实例化模板,则需要编译器和链接器服务作为运行时的一部分。这使得所需的运行时环境变得非常复杂 - 没有明显的优势。

显然,解释性C ++系统可能会推迟模板实例化,直到需要 - JIT(及时)处理。但是编译仍然在代码执行之前完成。

答案 2 :(得分:0)

我不习惯阅读标准,但Stroustrup的C ++编程语言非常精确。

A.9模板:给出模板声明的语法; type-parameter是class,typename或其他模板之一 - 因此类型是已知的,static。 (它不是动态的。如果C ++是一种动态语言,可以想象给出一个typeinfo对象。但这不是你的问题。)

C.13.8.3实例化绑定点:表示模板的实例化就在使用它的声明之前。

给出的示例涉及将模板定义中的名称解析为正确的范围。这在运行时很难做到!

e.g。来自Stroustrup C.13.8.3:

template<class T> void f(T a) { g(a); }

void g(int);

void h()
{
    extern g(double);
    f(2);
}

“这里f的实例化就在h()之前,所以f()中调用的g()是全局g(int)而不是本地g(double)。”

我想这并不排除JIT,但实际上,实例化模板f需要知道特定行的g的正确范围分辨率。正如Jonathan所说,在编译该单元时,您需要编译器的服务作为运行时的一部分,以及编译器中构建的完整上下文。如果那不是“编译时”的工作,我不知道是什么。

编辑: 这一切都依赖于古老版的C ++标准。