【发布时间】:2017-07-26 11:32:13
【问题描述】:
有没有办法让模板类的相同成员函数合并到最终的二进制文件中?我有一个可能支持特定功能的类,并且依赖于它,可能需要在成员函数内部执行一些额外的步骤:
template <uint32_t features>
class Driver {
static bool set (uint32_t value) {
/* do something required for every feature */
if (features & Feature::A)
/* do special things if Feature::A */
/* do something required for every feature */
if (features & Feature::B || features & Feature::C)
/* do something special for either Feature::B or Feature::C */
return true;
}
/* more, similar methods */
};
稍后在代码中,我将根据实际可用功能使用Driver<Feature::A>::set 或Driver<Feature::A | Feature::B>::set 之类的调用。到目前为止,所有这些都运行良好,只有使用 g++-5.4.0 -std=c++11 -O3 编译的发出代码不会合并相同的方法,我想如何使用它。在这个类中有多个函数,其中有主要的公共部分,确实会增加最终二进制文件的大小。虽然对公共部分使用私有函数会减少大小的开销,但我认为阅读起来并不友好:
template <uint32_t features>
class Driver {
static void _set_common_0 (value) {
/* do something required for every feature */
}
static bool set (uin32_t value) {
_set_common_0 (value);
if (features & Feature::A)
_set_special_0 (value);
_set_common_1 (value);
if (features & Feature::B || features & Feature::C)
_set_special_1 (value);
return true;
}
};
这也会带来问题,如果在其中一个特殊部分中存在“提前退出”路径,以前可以通过简单的return 完成,现在会以某种方式从子功能升级,引入进一步检查取决于那些子函数的返回值...
我想要的是,编译器为Driver<Feature::B>::set 和Driver<Feature::C>::set 发出(使用时)符号,但让它们指向相同的代码位置,因为它们在代码上是相同的。知道我该怎么做吗? (最好继续使用 c++11 并且不需要来自较新标准的功能)
编辑:为了澄清,我想知道为什么gcc 没有组合相同的指令序列(此处由模板实例生成)。据我了解,-ftree-tail-merge 至少应该替换那些跳转到相同实现/代码序列的那些(例如Driver<Feature::B>::set 和Driver<Feature::C>::set)。
【问题讨论】:
-
这里真的需要类模板吗?因为这不是应该使用模板的方式:您正在运行时检查编译时常量:
if (features & Feature::A) -
它并不是真正的编译时间常数。应该使用的特性是运行时依赖的,并且在编译期间是未知的。取决于运行时环境,我可以使用
Feature::A,也可以不使用。Driver<X>::set调用不是直接发出的,而是由在初始化期间分配的函数指针发出的,具体取决于检测到的环境特征。
标签: c++ c++11 templates optimization g++