何时实例化类模板的 vitual 方法
When are vitual methods of a class template instantiated?
C++标准是否说明了生成类模板虚拟方法代码的确切时间点?
请考虑以下示例:
class Interface
{
public:
virtual void f() = 0;
};
template <unsigned int V>
class A : public Interface
{
public:
virtual void f()
{
}
};
Interface* instantiate()
{
// class template instantiation with argument V=0
return new A<0>();
}
// specialization of f() for template argument V=0
template <> void A<0>::f()
{
cout << "Output from A<0>::f()" << endl;
};
int main()
{
Interface* i = instantiate();
i->f();
return 0;
}
类模板 A 声明了一个虚拟方法 f()。在我们的示例中,函数 instantiate() 在完成 A<0>::f() 的任何显式专用化之前隐式实例化类模板 A。在上面的示例中,专用化是在类模板 A 的隐式实例化发生后完成的。现在,至少我的ARM编译器和g++选择了A<0>::f()的专用版本,即main()程序将"A<0>::f()的输出"打印到屏幕上。
我是否总是可以确定,在类模板被隐式实例化之后,定义类模板的虚拟方法的专用化就足够了?如果观察到的行为得到C++标准的支持,我会感觉更好。我没有找到关于这个话题的任何明确声明。最接近的部分是 14.7.3/6,当涉及到虚拟方法时,这有点不具体:
如果模板、成员模板或类模板的成员显式专用,则 专业化应在首次使用该专业化之前声明,该专业化会导致隐含的 在发生这种使用的每个翻译单位中,进行这种使用;无需诊断。如果 程序不提供显式专业化的定义,并且该专业化用于 导致发生隐式实例化或成员是虚拟成员函数的方式, 程序格式不正确,无需诊断。永远不会为显式生成隐式实例化 已声明但未定义的专业化
我们很确定它是 UB。
在实践中:
new A<0>()
将生成对构造函数的调用,并且编译器需要它的定义才能可用。如果您尝试在此调用后专门化A<0>::A()
gcc 将出错:
error: specialization of ‘A<V>::A() [with V = 0]’ after instantiation
构造函数将具有设置类的多态标头的代码,该标头将包含指向 vtable 的指针。 在该 vtable 中将是 Interface::f
的条目,但它在这一点上甚至没有声明最终将填充该插槽的符号,您的显式专业化A<0>::f
- 所以它归结为实现质量问题 - 编译器是否在完成类类型的同时设计 vtable - 如果是这样,它是否能够在稍后的图。
非常不清楚。关于隐式实例化的相关部分是 14.7.1p2:
不幸的是,"[...]当在需要成员定义的上下文中引用该专用化时,成员的专用化是隐式实例化的;
需要定义存在"是一个完全未定义的术语,但我认为可以提出一个很好的论据,即"odr-used"至少是其中的一个子集。对于"odr-used",3.2p2 中的大文本墙说:
如果虚拟成员函数不是纯成员函数,则使用 odr。
换句话说,虚拟成员是由于其存在的(没有双关语)而必需的。
所以我认为可以提出一个论点,即编译器至少可以在实例化包含类的那一刻尝试实例化所有虚函数。我不知道有任何编译器这样做(AFAIK,除非被迫不这样做,否则它们都会延迟实例化直到翻译单元的末尾),但我认为您的代码严格不符合要求。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 何时实例化类模板的 vitual 方法