模板元编程 - 使用Enum Hack和静态Const的区别

时间:2010-01-31 17:47:54

标签: c++ templates metaprogramming

我想知道在使用模板元编程技术时使用静态const和枚举黑客有什么区别。

EX :(斐波那契通过TMP)

template< int n > struct TMPFib {
  static const int val =
    TMPFib< n-1 >::val + TMPFib< n-2 >::val;
};

template<> struct TMPFib< 1 > {
  static const int val = 1;
};

template<> struct TMPFib< 0 > {
  static const int val = 0;
};

VS

template< int n > struct TMPFib {
  enum {
    val = TMPFib< n-1 >::val + TMPFib< n-2 >::val
  };
};

template<> struct TMPFib< 1 > {
  enum { val = 1 };
};

template<> struct TMPFib< 0 > {
  enum { val = 0 };
};

为什么要使用一个而不是另一个?我已经读过枚举黑客是在类内部支持静态const之前使用的,但为什么现在使用呢?

4 个答案:

答案 0 :(得分:35)

枚举不是lvals,静态成员值是,如果通过引用传递,模板将被实例化:

void f(const int&);
f(TMPFib<1>::value);

如果你想进行纯编译时计算等,这是一个不希望的副作用。

主要的历史差异是枚举也适用于不支持成员值的类内初始化的编译器,现在大多数编译器都应该修复它。
enum和静态consts之间的编译速度也可能存在差异。

有关该主题的热门档案中的boost coding guidelinesolder thread中有一些详细信息。

答案 1 :(得分:12)

对于一些人来说,前者可能看起来不那么黑,而且更自然。如果你使用类,它也有为自己分配的内存,所以你可以拿取val的地址。

一些较旧的编译器可以更好地支持后者。

答案 2 :(得分:1)

另一方面,@Georg的答案是,当一个包含静态const变量的结构在专用模板中定义时,需要在源代码中声明它,以便链接器可以找到它并且实际上给它一个要引用的地址。这可能会不必要地(取决于所需的效果)导致不优雅的代码,特别是如果您尝试创建仅标头库。您可以通过将值转换为返回值的函数来解决它,这也可以将模板打开为运行时信息。

答案 3 :(得分:0)

“枚举破解”是对#define的更严格的限制,它有助于初始化枚举一次,并且在程序中的任何地方获取enum的地址都是不合法的,通常,使用#define的地址也是不合法的。如果您不想让人们得到您的整数常量的指针或引用,则enum是实施该约束的好方法。要了解如何对TMP进行暗示,就是在递归过程中,每个实例在递归过程中都将拥有自己的enum { val = 1 }副本,而每个val都将在循环中占有适当的位置。正如@Kornel Kisielewicz提到的那样,“ enum hack”也受到较早的编译器的支持,这些编译器禁止将初始值的类内规范指定为static const