当前位置: 首页 > 知识库问答 >
问题:

从模板中分解与参数无关的代码

广宏远
2023-03-14

本问题参考有效C书第44项。Scott Mayers指出,下面的模板类可能会导致代码膨胀,因为invert函数不一定依赖于模板参数n

template<typename T, std::size_t n>
class SquareMatrix
{   
public:
   void invert()
   {
      ...
   }
};

他建议反转函数可以在基类中分解如下。请注意,易失变量仅用于测试目的,以防止编译器优化所有内容。SquareMatrixBase::invert不应该做任何合理的事情。我只是想检查它的代码是否重复。

template<typename T>
class SquareMatrixBase
{
protected:
   void invert(std::size_t size)
   {
      volatile int var = size;
   }
};

template<typename T, std::size_t n>
class SquareMatrix : private SquareMatrixBase<T>
{
private:
   using SquareMatrixBase<T>::invert;

public:
   void invert()
   {
      invert(n);
   }
};

在这一点上,斯科特·梅耶斯说:

现在,许多(也许是所有)SquareMatrix的成员函数可以是对非内联基类版本的简单内联调用,这些版本与持有相同类型数据的所有其他矩阵共享,而不管它们的大小如何。

但是,我不明白为什么编译器不应该内联SquareMatrixBase::invert,这会导致代码膨胀。为什么 Scott Mayers 谈到“调用非内联基类版本”?就我现在而言,模板类的成员函数总是隐式地有资格内联,除非我强制编译器不要通过某些特定的指令这样做。

作为一个测试我的编译器,以下主要功能具有gcc和O3优化级别

int main()
{
   {
      SquareMatrix<int, 5> sm;
      sm.invert();
   }
   {
      SquareMatrix<int, 10> sm;
      sm.invert();
   }       
   return 0;
}

并且生成的目标代码清楚地显示BaseSquareMatrixBase::反转是内联的,从而导致重复的目标代码。

0000000000400400 <main>:
class SquareMatrixBase
{
protected:
   void invert(std::size_t size)
   {
      volatile int var = size;
  400400:       c7 44 24 f8 05 00 00    movl   $0x5,-0x8(%rsp)
  400407:       00 
   {
      SquareMatrix<int, 10> sm;
      sm.invert();
   }       
   return 0;
}
  400408:       31 c0                   xor    %eax,%eax
class SquareMatrixBase
{
protected:
   void invert(std::size_t size)
   {
      volatile int var = size;
  40040a:       c7 44 24 fc 0a 00 00    movl   $0xa,-0x4(%rsp)
  400411:       00 
   {
      SquareMatrix<int, 10> sm;
      sm.invert();
   }       
   return 0;
}
  400412:       c3                      retq 

我错过了什么?

共有1个答案

孔海超
2023-03-14

在这个具体的实例中,您和编译器都希望内联对< code>SquareMatrixBase的调用

 类似资料:
  • 上节的 Sstack 类模扳只用模板首部的类型参数,也可以使用无类型参数(non-type parameter),无类型参数可以有默认参数,一般将无类型参数当作Const处理。例如,模板首都可以取 int elements 参数,如下所示: template<class T,int elements> // note non-type parameter 然后下列声明: Stack<double,

  • 我有以下问题:一个类模板a,有几个模板参数,我想构建一个类B,它以a为模板参数,并提取a的第一个模板参数,以便在某种方法中使用它(想想从std::vector 中提取int并返回默认的int{})。 我知道这种天真的方法不会编译,但我不知道如何实现这样的东西。感谢任何提示。

  • 以下程序在C 20中编译良好: 但在C 17中,它会产生一个错误: 你能告诉我C20有什么变化让它工作吗?

  • std=C14的g在函子类的模板方法(本身不是模板)上给我一个“无法推断模板参数'Key'”错误。我不知道为什么。代码看起来应该可以工作。 我正在实现一个2-3树,它有一个采用函子的层次顺序遍历方法。操作人员tree23代码基本上是这样的: 级别顺序遍历调用仿函数的函数调用操作符,向其传递两个参数。 函子非常简单:

  • 本文向大家介绍C++函数模板与类模板实例解析,包括了C++函数模板与类模板实例解析的使用技巧和注意事项,需要的朋友参考一下 本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解。具体内容如下: 泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思。泛

  • 我有这样的情况 这是我自己的Vector类,构造函数模拟了Vector的行为(u可以通过使用interator提供的数据范围来构造它),但增加了一个要求,即容器是与正在构造的容器相同类型的模板。我有错误 5.cpp:16:36:错误:调用“Vector::Vector(Vector::Iterator,Vector::Iterator)”没有匹配函数5.cpp:16:36:注意:候选项是:包含在5