我正在维护一个大型模板类库,这些模板类基于任一float
或double
类型执行代数计算。许多类都有访问器方法(getter 和 setter)和其他运行少量代码的函数,因此当编译器找到它们的定义时,这些函数需要被限定为内联。相比之下,其他成员函数包含复杂的代码,因此最好调用而不是内联。
函数定义的很大一部分位于标头中,实际上位于标头包含的 .inl 文件中。但是也有许多类的函数定义通过显式实例化而愉快地存在于 .cpp 文件中float
和double
,这在库的情况下是一件好事(这里解释了原因)。最后,有相当多的类的函数定义在 .inl 文件(访问器方法)和 .cpp 文件(构造函数、析构函数和繁重的计算)中被破坏,这使得它们都很难维护。
只有当我知道一种可靠的方法来防止某些函数被内联时,我才会将我的所有类实现放在 .inl 文件中,或者如果inline
关键字可以强烈建议编译器内联某些函数,则在 .cpp 文件中,当然,它才不是。我真的希望库中的所有函数定义都驻留在 .cpp 文件中,但是由于访问器方法在整个库中被广泛使用,我必须确保它们在被引用时被内联,而不是被调用。
因此,在这方面,我的问题是:
标记模板函数的定义是否有意义
inline
,因为正如我最近在这里了解到的那样,无论它是否标记为,编译器都会自动将其限定为内联inline
?最重要的是,由于我希望将模板类的所有成员函数的定义聚集在一个文件中,无论是 .inl 还是 .cpp(在 .cpp 的情况下使用显式实例化),最好仍然能够提示编译器(MSVC 和 GCC)哪些函数应该被内联,哪些不应该被内联,确定模板函数是否可以实现这样的事情,我该如何实现这一点,或者,如果真的没有办法(我希望有),什么是最优化的折衷方案?
----------
EDIT1:我知道该inline
关键字只是对编译器内联函数的建议。
EDIT2:我真的知道。我喜欢向编译器提出建议。
EDIT3:我仍然知道。这不是问题所在。
----------
鉴于一些新的信息,还有第三个问题与第二个问题并驾齐驱。
3.如果编译器现在非常聪明,他们可以更好地选择应该内联哪个函数,应该调用哪个函数,并且能够生成链接时代码和链接时优化,这可以有效地让他们查看 .cpp -在链接时定位函数定义以决定其被内联或调用的命运,那么也许一个好的解决方案是将所有定义移动到相应的 .cpp 文件中?
----------
那么结论是什么?
首先,我感谢 Daniel Trebbien 和 Jonathan Wakely 的结构化和有根据的回答。两者都赞成,但只能选择一个。然而,没有一个给出的答案对我来说是一个可以接受的解决方案,所以选择的答案恰好是比其他人更能帮助我做出最终决定的答案,接下来会为感兴趣的人解释其细节。
好吧,由于我一直更重视代码的性能,而不是维护和开发的便利程度,在我看来,最可接受的折衷方案是移动每个访问器方法和其他轻量级成员函数将模板类放入相应标头包含的 .inl 文件中,用inline
关键字标记这些函数,以尝试为编译器提供良好的提示(或为内联强制提供关键字),并将其余函数移动到相应的.cpp 文件。
将所有成员函数定义都放在 .cpp 文件中会阻碍轻量级函数的内联,同时释放链接时优化的一些问题,正如 Daniel Trebbien 为 MSVC(在较早的开发阶段)和 Jonathan Wakely 为 GCC 确定的那样(在目前的发展阶段)。并且将所有函数定义都放在头文件(或 .inl 文件)中并不会超过将每个类的实现分类到 .inl 和 .cpp 文件中以及该决定的额外副作用的总结好处:它将确保库的客户端只能看到原始访问器方法的代码,而二进制文件中隐藏了更多有趣的东西(确保这不是主要原因,但是对于任何熟悉软件库的人来说,这一点都很明显)。inline
鼓励函数的内联状态(还不知道关键字应该在两个地方还是在这种特殊情况下只在一个地方)。