虚拟化对类模板成员使用的影响

14
我(模糊地)知道,如果没有使用,模板将不会被实例化。例如,即使当T = int时,下面的代码也可以编译通过,因为T :: type在这种情况下是无意义的。
template<typename T>
struct A
{
    void f() { using type = typename T::type; }
};

A<int> a; //ok

它能够编译是因为f()没有被使用,所以它没有被实例化 - 因此T::type的有效性仍未经检查。即使其他一些成员函数g()调用f()也无所谓。
template<typename T>
struct A
{
    void f() { using type = typename T::type; }

    void g() { f(); } //Is f() still unused?
};

A<int> a; //ok

这也会编译罚款。但是在这里我意识到了我对"使用"定义的模糊理解。我问:

  • f()仍然未被使用吗?具体来说是怎样的?

我可以清楚地看到它在g()内部被使用。但是我想,由于g()没有被使用,从实例化的角度来看,f()也没有被使用。这似乎已经足够合理。

但是如果我给g()添加virtual关键字,它将无法编译:

template<typename T>
struct A
{
    void f() { using type = typename T::type; }

    virtual void g() { f(); } //Now f() is used? How exactly?
};

A<int> a; //error

它导致编译错误,因为现在它试图实例化f()。我不理解这种行为。
有人能解释一下吗?特别是virtual关键字对类模板成员的"use"定义的影响。

1
如果我没记错的话,virtual 强制实例化成员函数,因为现在静态地评估这个函数是否会被使用几乎是不可能的。实际上,你要求创建一个填充有指向函数的指针的虚函数表... 所以这个函数需要存在,这样我们才能取一个指向它的指针。 - Matthieu M.
结构体模板只有在使用时才会被实例化。它要么是整个结构体,要么就什么都没有。这与 g 或 f 没有任何关系。 - Sarien
1
@Sarien:是的,模板类的成员函数只有在ODR使用时才会被实例化。 - Matthieu M.
@Sarien:即使你不使用它们,实例化所有成员将非常愚蠢。幸运的是,C++很聪明,只会实例化你使用的内容。 - Nawaz
1个回答

10
快速查看3.2 [basic.def.odr] 可得:
3/ [...] 如果虚成员函数不是纯虚的,则会odr-used。[...]
我还在14.7.1 [temp.inst] 中找到了:
10/ 实现不应隐式实例化函数模板、成员模板、非虚拟成员函数、成员类或类模板的静态数据成员,如果它不需要实例化。如果否则不实例化虚拟成员函数,则是否有具体实现是未指定的。(强调属于我)
所以...我会认为一个virtual方法很可能总是被实例化。
从实际角度来看,我期望编译器在实例化类时实例化模板类的虚表;因此立即实例化该类的所有虚成员函数(以便可以从虚表中引用这些函数)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接