从模板中分解与参数无关的代码
Factoring parameter-independent code out of templates
这个问题指的是有效C++书中的第44项。Scott Mayers指出,以下模板类可能会导致代码膨胀,因为inverse函数不一定取决于模板参数n。不幸的是,具有不同n值的多个模板实例,如SquareMatrix<int,5>以及SquareMatrix<int,10>也会生成反转函数的多个实例,从而生成比实际情况更大的目标代码
template<typename T, std::size_t n>
class SquareMatrix
{
public:
void invert()
{
...
}
};
他建议,inverse函数可以在基类中进行分解,如下所示。请注意,volatile var只是用于测试目的,以防止编译器优化所有内容。SquareMatrixBase::inverse不应该做任何合理的事情。我只是想检查一下它的代码是否重复。
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);
}
};
在这一点上,Scott Mayers说:
现在,SquareMatrix的许多——也许是所有——成员函数可以对共享的非内联基类版本的简单内联调用所有其他矩阵都包含相同类型的数据,而不管它们的大小。
然而,我不明白为什么编译器不应该内联SquareMatrixBase::invert,这会导致代码膨胀。为什么Scott Mayers谈论"对非内联基类版本的调用"?到目前为止,模板类的成员函数总是隐式符合内联条件,除非我通过某些特定指令强制编译器不要这样做。
作为测试I编译器,以下主要功能具有gcc和O3优化级别
int main()
{
{
SquareMatrix<int, 5> sm;
sm.invert();
}
{
SquareMatrix<int, 10> sm;
sm.invert();
}
return 0;
}
生成的对象代码清楚地表明BaseSquareMatrixBase::invert是内联的,因此导致了重复的对象代码。
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
我错过了什么?
在这个具体实例中,您和编译器都希望内联对SquareMatrixBase<int>::invert()
的调用,因为它太小了。使用更大的invert()
函数,编译器将在内联或调用之间进行权衡——看看gcc对-Os做了什么会很有趣,例如,对完全实现的invert()
做了什么——但如果基类不是模板化类(或者如果您只计划支持有限数量的实例化),您可以选择通过在不同的编译单元中提供实现来强制解决问题。
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 根据编译时参数在 C 中重复代码
- 扩展C++生成的代码的模板参数类型名称
- 将函数作为参数传递以避免重复代码
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- C++基于输入参数的动态代码生成
- 调用参数不是原子参数的函数是此代码引发异常的原因吗?
- 引入参数化构造函数后显示 LNK 2019 未解析外部符号的代码错误
- 在 Metal 着色器代码中,如何定义函数的 in/out 参数变量?
- C++17.处理使用 auto 相关的模板参数.代码排序困难
- 为什么EclipseCDT代码格式化程序有时会在模板参数中引入空格
- 我写了一个类,它总是将其函数参数委托给它的成员,我该如何改进代码
- 编译器是否C++具有相同模板参数集的每个模板类实例生成代码?
- 如何将char数组声明为函数参数?或告诉我此代码中还有其他问题?
- 我的代码在作为参数传入 .begin() 时不起作用,但在我将 .begin() 转换为迭代器后工作
- 如何基于构造函数参数模板化类成员函数的代码
- 在存在错误代码的情况下输出参数与 NRVO
- 在完美转发函数中公开参数类型,避免代码重复
- 中断长代码 snprintf 格式和参数
- 将代码移出类定义时未扩展参数包