【发布时间】:2015-01-23 16:14:42
【问题描述】:
我希望更好地了解编译器何时会隐式实例化成员函数模板。
考虑以下示例:
// example.h
struct Parent {
virtual void foo(double) {}
};
struct Child : Parent {
void foo(double d) { bar(d); }
template<typename T> void bar(T);
virtual void baz();
};
// example.cpp
#include "example.h"
template <typename T>
void Child::bar(T) {}
void Child::baz() {}
用[g++|clang++] -c example.cpp 编译它,GCC 和clang 都隐式实例化函数模板Child::bar<double>。但是,以下看似微小的更改阻止了这一点:
- 使
foo不是虚拟的 - 使
Child不继承自Parent - 删除
baz - 使
baz不是虚拟的 - 用标题中的声明定义
baz
对于何时发生隐式实例化是否有任何合理简洁的解释,或者我是否需要翻阅标准的副本?我已经搜索了与隐式实例化有关的其他问题,但没有找到太多。我找到的最接近的是this question,但它是关于类模板中的虚函数(不是成员函数模板)。
明确一点:我知道可以通过在标题中包含定义或显式实例化我需要的模板来避免此问题。当深入研究为什么一个类(我无意中省略了其显式实例化)仍然愉快地编译和链接时,这只是作为一个好奇点出现。
【问题讨论】:
-
它很简单——它们仅在被调用时被实例化。您拥有的不同案例集仅决定何时实际需要该参考。当你有一个虚函数时,它需要在虚表中创建一个条目。在 foo 中调用 bar 会强制它实例化它。如果没有 baz,它就不需要 Child 的 vtable。使 baz 内联不应该影响它 - 这可能是优化的结果?如果你从 Child 继承了一个孙子并给它一个虚拟函数 - 现在内联 baz 不应该阻止实例化