是否为未使用的模板类方法生成了对象代码?

时间:2008-10-08 14:41:17

标签: c++ templates footprint

我有一个C ++模板类,可以使用3种不同的类型参数进行实例化。有一种方法,该类只需要对其中一种类型进行处理,而且不会使用其他两种类型进行调用。

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

3 个答案:

答案 0 :(得分:21)

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

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

  

实现不应隐式实例化函数模板,变量模板,成员   模板,非虚成员函数,成员类,类模板的静态数据成员,或   除非需要进行此类实例化,否则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()这样的东西。此功能通常用作模板元编程工具。

但是,请注意,模板的“实例化”与生成的对象代码的数量并不直接相关。这取决于您的编译器/链接器实现。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

通常,是的。

所有编译器都知道你的程序可以创建每个类的至少一个实例。但它不知道你将对这些实例做些什么。因此几乎可以肯定地生成代码。

也就是说,如果所讨论的方法是虚拟的,并且从未被调用过,链接器可以使用其正常的死代码删除功能删除它们。因此生成的(和编译的)代码将不在最终的EXE中。

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