有没有办法让模板化类的相同成员函数在最终二进制文件中合并?我有一个可能支持特定功能并依赖于它的类,可能需要在成员函数内部执行一些额外的步骤:
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
至少应该替换那些跳转到相同的实现/代码序列(e.q。Driver<Feature::B>::set
和Driver<Feature::C>::set
)。
答案 0 :(得分:0)
根据您发布的代码,我很清楚您是否滥用了模板。正确的方法是定义Driver
:
template <uint32_t features>
class Driver; // There may be some default implementation, but it is not necessary
// Specialize for feature A only
template <>
class Driver<Feature::A> {
bool set (uint32_t value) {
/* do special things for Feature::A */
/* do something required for every feature */
return true;
}
};
// Specialize for feature B only
template <>
class Driver<Feature::B> {
bool set (uint32_t value) {
/* do special things for Feature::B */
/* do something required for every feature */
return true;
}
};
// Specialize for features A and B
template <>
class Driver<Feature::A | Feature::B> {
bool set (uint32_t value) {
/* do special things for Feature::A */
/* do special things for Feature::B */
/* do something required for every feature */
return true;
}
};
模板方法的好处是,由于检查是否启用了某些功能,因此不会产生运行时开销。当然,如果有很多功能,将会有大量的功能组合;因此输出二进制的膨胀。这就是为什么我建议摆脱类模板并使用运行时函数参数;例如,将要素传递给构造函数:
class Driver {
private:
uint32_t features_;
public:
Driver(uint32_t features) : features_(features) {}
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;
}
};