模板实际上必须是编译时构造吗?
C++ 标准实际上是否强制要求模板必须在编译时而不是运行时实例化?
如果不是,我们使用它是否纯粹是因为这样做显然有意义?或者是否有一些实际原因会在理论上阻止现有的可以在运行时实例化模板的实现?
Does the C++ Standard actually mandate that templates must be instantiated at compile-time, not run-time?
If not, is it a convention that we use purely because it obviously makes sense to do it that way? Or is there some practical reason that would, theoretically, prevent an implementation from existing that can instantiate templates at run-time?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
所有标准要求的是可观察的行为就像在程序开始运行之前实例化模板一样。例如,任何错误都必须在编译的某个阶段或至少在运行时之前触发消息。理论上,编译器可能会将完整实例化推迟到运行时,但实际上,它必须在编译时完成大部分工作,才能确保出现任何潜在的错误消息。
从更严格的意义上来说,该标准将“翻译”视为一个单位;实现可以,并且实现已经(我认为有些实现仍然这样做)将实例化推迟到链接时间。当涉及动态链接时,这会导致有趣的问题。但标准对此保持沉默:就标准而言,动态链接实际上是未定义的行为,因此取决于实现。
然而,最终:实例化模板是编译器执行的最昂贵的操作之一,并且需要非常大且复杂的机制。没有供应商愿意将其强加于可执行文件。因此,无论存在什么漏洞,都不要指望很快就会看到运行时实例化。特别是因为它不会给你买任何东西:标准要求所有模板都可以在编译时实例化,因此你无法以某种方式依赖于运行时参数实例化模板并且仍然符合标准。
All the standard requires is that the observable behavior be as if the templates were instantiated before the program started to run. Any errors, for example, would have to trigger a message in some phase of the compilation, or at least before runtime. In theory, a compiler could probably defer full instantiation until runtime, but in practice, it would have to have done most of the work at compile time anyway, in order to be sure that any potential error messages appeared.
In a stricter sense, the standard considers "translation" as a unit; an implementation could, and implementations have (and I think some still do) defer instantiation until link time. Which leads to interesting questions when dynamic linking is involved. But the standard is silent about that: dynamic linking is really undefined behavior, as far as the standard is concerned, so it is up to the implementation.
In the end, however: instantiating templates is one of the most expensive operations a compiler does, and requires a very large and complex mechanism. Which no vendor wants to impose on an executable. So regardless of the loopholes, don't expect to see run time instantiation any time soon. Especially as it wouldn't buy you anything anyway: the standard requires that all templates can be instantiated at compile time, so you couldn't instantiate a template somehow dependent on a runtime argument and still be standard conform.
您无法在运行时(当程序运行时)在 C++ 程序中创建类型;它们在编译时都是已知的。即使动态加载的共享库也不会改变这一点;库中的类型集在编译时(编译库时)是已知的,并且加载程序必须能够处理库公开的类型。
因此,不需要在运行时进行模板评估;这些信息在编译时都是已知的。
如果要在运行时实例化模板,则需要编译器和链接器服务作为运行时的一部分。这使得所需的运行时环境变得非常复杂——没有明显的优势。
显然,解释性 C++ 系统可以(或许会)将模板实例化推迟到需要时——JIT(及时)处理。但编译仍然是在代码执行之前完成的。
You can't create types in a C++ program at run time (while it is running); they are all known at compile time. Even dynamically loaded shared libraries don't change that; the set of types in the library is known at compile time (when the library is compiled), and the loading program must be able to handle the types that the library exposes.
So, there is no need for template evaluation at run time; the information is all known at compile time.
If you were to instantiate templates at run time, you'd need the compiler and the linker services as part of the run time. That greatly complicates the required run time environment - to no obvious advantage.
Clearly, an interpretive C++ system could, probably would, defer the template instantiation until needed - JIT (just in time) processing. But the compilation is still done before the code is executed.
我没有阅读标准的习惯,但 Stroustrup 的 C++ 编程语言非常精确。
A.9 模板:给出模板声明的语法;类型参数是类、类型名或另一个模板之一 - 因此类型是已知的、静态的。 (它不是动态的。如果 C++ 是一种动态语言,人们可以想象给出一个 typeinfo 对象。但这不是你的问题。)
C.13.8.3 实例化点绑定:表示模板的实例化点就在之前使用它的声明。
给出的示例涉及将模板定义中的名称解析到正确的范围。这在运行时很难做到!
例如,来自 Stroustrup C.13.8.3:
“这里 f 的实例化点就在 h() 之前,因此 f() 中调用的 g() 是全局 g(int) 而不是局部 g(double)。 ”
我想这并不排除 JIT,但实际上,实例化模板 f 需要知道 g 在特定行的正确作用域分辨率。正如乔纳森所说,您需要编译器的服务作为运行时的一部分,以及编译该单元时在编译器中构建的完整上下文。如果这不是“编译时”工作,我不知道什么才是。
编辑:
这一切都依赖于 C++ 标准的古董版本。
I'm not in the habit of reading the standard, but Stroustrup's C++ Programming Language is usefully precise.
A.9 Templates: gives the grammar for template declaration; the type-parameter is one of class, typename, or another template - so the type is known, static. (it's not dynamic. one could imagine giving a typeinfo object if C++ were a dynamic language. But that wasn't your question.)
C.13.8.3 Point of Instantiation Binding: says that the point of instantiation for a template is just before the declaration using it.
The example given is concerned with resolving names in the template definition to the correct scope. This would be very hard to do at run-time!
e.g. from Stroustrup C.13.8.3:
"Here the point of instantiation for f is just before h(), so the g() called in f() is the global g(int) rather than the local g(double)."
I guess this doesn't rule out JIT, but as a practical matter, instantiating the template f requires knowing the correct scoped resolution of g at a particular line. As Jonathan says, you'd need the compiler's services as part of the run-time, along with the full context built up in the compiler while compiling that unit. If that's not a "compile-time" job, I don't know what is.
EDIT:
This all relies on an antique version of the C++ standard.