5

我正在阅读 pbrt,它定义了一个类型:

template <int nSpectrumSamples>
class CoefficientSpectrum;
class RGBSpectrum : public CoefficientSpectrum<3> {
    using CoefficientSpectrum<3>::c;
typedef RGBSpectrum Spectrum;
// typedef SampledSpectrum Spectrum;

并且作者说:

“我们没有编写系统,以便可以在运行时解决使用哪个 Spectrum 实现的选择;要切换到不同的表示,必须重新编译整个系统。这种设计的一个优点是,许多不同的 Spectrum方法可以实现为可以由编译器内联的短函数,而不是作为必须通过相对较慢的虚拟方法调用机制调用的独立函数。内联这些常用的短函数可以带来实质性的改进在性能上。”

1.为什么模板可以内联功能而普通方式不能?

2.为什么普通方式必须使用虚拟方式?

整个头文件的链接: https ://github.com/mmp/pbrt-v3/blob/master/src/core/spectrum.h

4

1 回答 1

7

要内联函数调用,编译器必须知道 1. 调用了哪个函数,以及 2. 该函数的确切代码。函数的全部目的virtual是将调用哪个函数的选择推迟到运行时,因此编译器只能通过复杂的优化技术获得上述信息,这些技术需要非常具体的情况1

模板和虚函数(即多态)都是编码抽象的工具。使用 a 的代码CoefficientSpectrum并不真正关心光谱的实现细节,只关心您可以将其转换为 RGB 和从 RGB 转换——这就是它使用抽象的原因(以避免为每种光谱重复代码)。正如您引用的评论中所解释的,在这里使用多态进行抽象意味着编译器很难优化代码,因为它从根本上将实现的选择推迟到运行时(这有时很有用,但在这里并不是绝对必要的)。通过要求在编译时选择实现,编译器可以轻松地优化(即内联)代码。

1例如,一些编译器能够优化掉std::function抽象,这通常使用多态来进行类型擦除。当然,这只有在所有必要信息都可用的情况下才有效。

于 2018-11-28T08:46:38.663 回答