g ++:合并模板成员函数实例

时间:2017-03-06 14:36:19

标签: c++ c++11 templates optimization g++

有没有办法让模板化类的相同成员函数在最终二进制文件中合并?我有一个可能支持特定功能并依赖于它的类,可能需要在成员函数内部执行一些额外的步骤:

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>::setDriver<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>::setDriver<Feature::C>::set发出(使用中)符号,但让它们指向相同的代码位置,因为它们通过代码相同。知道我怎么能这样做吗? (最好是使用c ++ 11并且不需要更新标准的功能)

编辑:为了澄清,我想知道为什么相同的指令序列(由模板实例在此处生成)不由gcc组合。根据我的理解,-ftree-tail-merge至少应该替换那些跳转到相同的实现/代码序列(e.q。Driver<Feature::B>::setDriver<Feature::C>::set)。

1 个答案:

答案 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;
   }
};