【问题标题】:Why do template classes allow member functions which cannot compile?为什么模板类允许无法编译的成员函数?
【发布时间】:2015-07-09 21:42:21
【问题描述】:
class P
{
};

template< typename P >
class C : public P
{
  public:
  void f()
  {
    P::f();
  }
};

int main() {
  C<P> c1;
  return 0;
}

以防我的问题留下任何误解的余地,这里有一个代码示例。如果C 不是 模板化但直接从P 继承,则示例将无法编译,因为显然函数f() 试图调用基类P 上的函数,这是非存在。

但是,如果 C 被模板化,那么只有在实际调用 f() 时才会使用它。

我想知道为什么会有这种差异。在这两种情况下,f() 都将是死代码并被剥离,但在非模板场景中程序格式不正确。

【问题讨论】:

  • 请注意,您可以通过显式实例化C&lt;P&gt; 来触发错误。
  • 它从来没有被编译过,所以它没有被“允许”,它根本不存在于文本形式之外。

标签: c++ templates


【解决方案1】:

实际上,您发布的程序并非格式错误。而“隐式实例化”C&lt;P&gt; c1; 实例化所有成员声明

成员的特化在引用特化时被隐式实例化 在需要成员定义存在的上下文中

[N4140, 14.7.1(2)] 由于您从不使用C&lt;P&gt;::f,因此永远不需要其定义,因此永远不会实例化。

这与“显式实例化”不同

template class C<P>;

这将实例化C&lt;P&gt; 的所有成员的定义,从而导致错误。

【讨论】:

    【解决方案2】:

    因为只允许使用实际上格式正确的函数是有意义的。

    vector::push_back(const T&amp;) 为例,这要求T 是可复制的。但是即使T 是可移动的不可复制类型,您仍然可以使用大部分vector

    【讨论】:

      【解决方案3】:

      在模板类内部,标识符P是一个模板参数类型名,它引用之前定义的class P。所以你不能说P::f() 不存在,因为你不知道参数P 会被哪个类代替。

      然后,当您调用模板来声明c1 变量时,不需要该函数,因此没有“死代码”——只有一个模板,它从未扩展为实际代码。

      【讨论】:

        【解决方案4】:

        如果我编写一个继承自 P 的非模板类,那么从成员函数调用该类上不存在的函数显然是一个错误,因为它没有任何用处。

        但是,如果C 是一个模板类,那么该错误调用可能对其他一些P 有效。也许该成员函数代表了支持某些给定接口的类型的一些扩展功能。 C 可以从一些我在为P 实例化时不知道的外部库中实例化。因此,为模板类中可能对某些类型有效的未使用函数引发编译器错误将限制模板的表达能力。它还降低了编译时间、二进制大小等,因为不需要为不使用的类型生成不需要的模板函数。

        【讨论】:

          【解决方案5】:

          不使用变量C&lt;P&gt; c1;,并且永远不会调用C::f() 函数。编译器在使用之前不会创建函数体。这是一个可以加快编译速度的简单优化。

          【讨论】:

            猜你喜欢
            • 2019-05-20
            • 1970-01-01
            • 1970-01-01
            • 2013-09-05
            • 1970-01-01
            • 2020-08-17
            • 1970-01-01
            • 2020-02-05
            • 1970-01-01
            相关资源
            最近更新 更多