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

C++ g++;:合并模板成员函数实例,c++,c++11,templates,optimization,g++,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)

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

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


编辑:为了澄清,我想知道为什么相同的指令序列(在这里由模板实例生成)不是由
gcc
组合而成的。就我的理解而言,
-ftree-tail merge
至少应该用跳转到相同的实现/代码序列(例如
Driver::set
Driver::set
)来替换这些实现/代码序列。

从您发布的代码中,我很清楚您误用了模板。正确的方法是定义
驱动程序的部分专门化:

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

你真的需要一个类模板吗?因为这不是模板的使用方式:您正在运行时检查编译时常量:
if(features&Feature::A)
它实际上不是编译时常量。应该使用的功能依赖于运行时,在编译过程中是未知的。取决于运行时环境,我可以使用
Feature::A
,也可以不使用它。
Driver::set
调用不是直接发出的,而是由函数指针发出的,该指针在初始化过程中根据检测到的环境功能进行分配。我看不出您的第一个解决方案对我的给定解决方案有什么好处。在不断折叠之后,模板实例化的代码将是相同的——使用回退,公共部分必须由您的解决方案编写多次(在每个主体中)。随着未来的变化,一个人可能会错过一个可能会带来问题/错误的主体。模板用于减少运行时开销,因为我知道在每次调用时哪些功能可用。我在开始时有一个选择,以选择正确的控制流。问题是,为什么
gcc
不合并相同的代码部分。你是对的。这就是为什么这里不需要模板,而应该使用第二种解决方案。我只是举了一个例子,说明如果您决定需要模板,应该如何使用它们。在第二个解决方案中,我引入了不需要/不需要的运行时检查。我现在已经在编译时为每个调用一个功能,我有可用的功能,所以这应该是可能的(或也是)。剩下的问题是,如何使
gcc
组合产生相同代码的模板实例。例如,
Driver::set
Driver::set
将是相同的,但发出两次-导致大小增加两倍。至于您说我应该使用模板的方式:与我的解决方案相比,您的解决方案有什么好处(因此我将使用您的解决方案)?好处是没有对功能进行运行时检查(即,类似
if(features&Feature::A)
)。它们存在于类模板中,并使模板参数毫无用处。如果您非常关心性能,那么您可能只希望编译器优化您的模板实例化并删除不必要的检查,检查的形式为
If(true)
If(false)
。但我认为这是一种非常落后的编程方式。对于C++ 17,你应该有多个手写模板专业;在C++17中,如果constexpr
,您可以使用
。如果您确实想坚持使用模板解决方案,您可以尝试在GCC中启用
-Os
优化选项。这可能会减少输出二进制大小。
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;
   }
};