代码之家  ›  专栏  ›  技术社区  ›  hsivonen

是否为未使用的模板类方法生成目标代码?

  •  14
  • hsivonen  · 技术社区  · 17 年前

    我有一个C++模板类,它用3个不同的类型参数实例化。类只需要为其中一个类型提供一个方法,并且该方法永远不会与其他两个类型一起调用。

    该方法的目标代码会生成三次(针对模板实例化的所有类型),还是只生成一次(针对实际使用的类型)?

    3 回复  |  直到 17 年前
        1
  •  24
  •   Peter Coulton    9 年前

    当实例化类模板时,虚拟成员函数会被实例化,但非虚拟成员函数只有在被调用时才会被实例化。

    这在C++标准的[temp.inst]中有所涉及(在C++11中,这是§14.7.1/10。在C++14中,它是§14.7.1/11,在C++17中是§17.7.1/9。摘录自下面的C++17)

    实现不应隐式实例化函数模板、变量模板、成员 模板、非虚拟成员函数、成员类、类模板的静态数据成员,或 a的子陈述 constexpr if语句(9.4.1),除非需要实例化

    还要注意,即使某些成员函数对于给定的模板参数不可实例化,也可以实例化类模板。例如:

    template <class T>
    class Xyzzy
    {
    public:
        void CallFoo() { t.foo(); }  // Invoke T::foo()
        void CallBar() { t.bar(); }  // Invoke T::bar()
    
    private:
        T t;
    };
    
    class FooBar
    {
    public:
        void foo() { ... }
        void bar() { ... }
    };
    
    class BarOnly
    {
    public:
        void bar() { ... }
    };
    
    int main(int argc, const char** argv)
    {
        Xyzzy<FooBar>  foobar;    // Xyzzy<FooBar> is instantiated
        Xyzzy<BarOnly> baronly;   // Xyzzy<BarOnly> is instantiated
    
        foobar.CallFoo();         // Calls FooBar::foo()
        foobar.CallBar();         // Calls FooBar::bar()
    
        baronly.CallBar();        // Calls BarOnly::bar()
    
        return 0;
    }
    

    这是有效的,即使Xyzzy::CallFoo()不可实例化,因为不存在BarOnly::foo()这样的东西。此功能通常用作模板元编程工具。

    然而,请注意,模板的“实例化”与生成的目标代码量没有直接关系。这将取决于你的编译器/链接器实现。

        2
  •  2
  •   Nick    17 年前

    我认为这取决于编译器和设置。例如,我相信MSVC6生成了所有内容,但VS2005没有。规范说编译器不应该,但在现实世界中,这取决于实际的编译器(例如,MSVC6的boost中有许多解决方法)。如果启用了/opt:ref,链接器可以删除未引用的函数(对于VS,其他编译器也有等效的选项)。

        3
  •  1
  •   Jeff B    17 年前

    通常,是的。

    编译器真正知道的是,你的程序可以创建每个类的至少一个实例。但它不知道你会如何处理这些实例。因此,代码几乎肯定会生成。

    也就是说,如果所讨论的方法是 虚拟的,永远不会被调用 连接器 可以使用其正常的死代码删除功能删除它们。因此,生成(和编译)的代码不会出现在最终的EXE中。

    此外,这在很大程度上取决于所使用的C++编译器,因为它们并不完全相同。

    推荐文章