当生成用于类模板的虚拟方法的代码时,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 ::f()的任何专门化之前,隐式实例化了类模板A。在上面的示例中,特化是在类模板A的隐式实例化发生之后完成的。现在,至少我的ARM编译器和g++选择了A ::f()的专用版本。 e。 main()程序在屏幕上显示“A ::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
构造函数将具有用于设置类的多态 header 的代码,该 header 将包含指向vtable的指针。在该vtable中将是
Interface::f
的条目,但此时甚至还没有声明将最终填充该插槽的符号,即显式的特化A<0>::f
-因此归结为实现质量问题-编译器在完成类类型的同时设计vtable-如果可以的话,它有能力在以后的TU中修复该vtable的新声明的成员。