当生成类模板的虚拟方法的代码时,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()。在我们的示例中,函数实例化()隐式地实例化类模板A,然后执行A<0>::f()的任何显式专门化。在上面的例子中,专门化是在类模板A的隐式实例化之后完成的。现在,至少我的ARM编译器和g++选择了A<0>::f()的专门版本,即主()程序将“输出从A<0>::f()”打印到屏幕上。
我能否始终确保,在类模板隐式实例化之后定义类模板的虚拟方法的专门化就足够了?如果观察到的行为得到C++标准的支持,我会感觉更好。我没有找到任何关于这个问题的明确声明。最接近的部分是14.7.3/6,这在虚拟方法方面有些不明确:
如果模板、成员模板或类模板的成员是明确专门化的,则应在首次使用该专门化之前声明该专门化,这将导致在发生这种使用的每个翻译单元中发生隐式instan- tiation;不需要诊断。如果程序没有为显式专门化提供定义,并且使用专门化的方式会导致隐式实例化发生,或者成员是虚拟成员函数,则程序是格式错误的,不需要诊断。不为声明但未定义的显式专门化生成隐式实例化。
发布于 2013-09-19 16:43:27
我们很确定是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 --如果是这样的话,它是否能够在TU中修复该vtable的一个新声明的成员。
发布于 2013-09-19 15:58:42
这方面的标准还很不清楚。有关隐式实例化的相关章节为14.7.1p2:
..。当专门化在要求成员定义存在的上下文中引用时,成员的专门化被隐式实例化;
不幸的是,“要求定义存在”是一个完全没有定义的术语,但我认为,“odr使用的”至少是其中的一个子集,这是一个很好的论点。对于"odr-used",3.2p2中文字的大墙写着:
如果虚拟成员函数不是纯的,则使用odr。
换句话说,虚拟成员仅仅是他们存在的美德(不是双关语)所要求的。
因此,我认为可以提出一个论点,即编译器在实例化包含类时至少可以尝试实例化所有虚拟函数。我不知道有任何编译器会这样做(AFAIK,它们都将实例化延迟到翻译单元的末尾,除非强制不这样做),但我认为您的代码完全不符合要求。
https://stackoverflow.com/questions/18899102
复制相似问题