为什么 MSVC 编译器将模板实例化二进制文件放入程序集中?

Nim*_*rab 6 c++ templates

我在 MSVC 编译器中遇到了一些奇怪的事情。

它将函数模板定义放在汇编中,而优化消除了对它们的需要。看起来 Clang 和 GCC 完全成功地删除了函数定义,但 MSVC 却没有。

可以修复吗?

主要.cpp:

#include <iostream>

template <int n> int value() noexcept
{
    return n;
}

int main()
{
    return value<5>() + value<10>();
}
Run Code Online (Sandbox Code Playgroud)

集会:

int value<5>(void) PROC                                ; value<5>, COMDAT
        mov     eax, 5
        ret     0
int value<5>(void) ENDP                                ; value<5>

int value<10>(void) PROC                                ; value<10>, COMDAT
        mov     eax, 10
        ret     0
int value<10>(void) ENDP                                ; value<10>

main    PROC                                            ; COMDAT
        mov     eax, 15
        ret     0
main    ENDP
Run Code Online (Sandbox Code Playgroud)

godbolt 上的示例代码

Chr*_*sMM 7

交换机/FA为每个翻译单元生成列表文件。由于这是在链接阶段之前,MSVC 无法确定程序中其他任何地方是否需要这两个函数,因此仍然包含在生成的 .asm 文件中(注意:这可能是 MS 方面的简单性,因为它可以将模板视为生成的 .obj 文件中的常规函数​​,尽管实际上没有实际需要将它们存储在 .obj 文件中,正如 user17732522 在评论中指出的那样)。

在链接过程中,MSVC 确定这些函数实际上在其他任何地方都没有实际使用/需要,因此可以被消除(即使它们在其他地方使用,因为结果可以在编译时确定,它们仍然会被消除)编译后的可执行文件。

为了查看最终编译的可执行文件中的内容,您可以通过反汇编程序查看可执行文件。使用 MSVC 执行此操作的示例是在 main 函数中放置一个断点,运行它,然后当断点被命中时,右键单击并“查看反汇编”。在这里,您将看到这两个函数不再存在。

您还可以使用选项生成Mapfile /MAP,这也显示它不存在。


如果我正确地阅读文档,似乎那些 MS 选择包含模板类和函数的显式实例化,因为它在创建库时“很有用”。但未实例化的模板不会放入 obj 文件中。