模板元编程 - 使用 Enum Hack 和 Static Const 的区别
Posted
技术标签:
【中文标题】模板元编程 - 使用 Enum Hack 和 Static Const 的区别【英文标题】:Template Metaprogramming - Difference Between Using Enum Hack and Static Const 【发布时间】:2011-01-11 11:21:48 【问题描述】:我想知道在使用模板元编程技术时使用静态 const 和 enum hack 之间有什么区别。
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;
;
对比
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 之前使用了 enum hack,但是为什么现在使用它呢?
【问题讨论】:
+1:确实是一个很好的问题,我也想看看答案会是什么,除了显而易见的。 static const 允许 int 以外的类型。例如双倍。 【参考方案1】:"enum hack" 对#define
更受限制且足够接近,这有助于将枚举初始化一次,在程序中的任何位置获取enum
的地址是不合法的,而且通常不合法取#define
的地址。如果您不想让人们获得指向您的整数常量之一的指针或引用,enum
是实施该约束的好方法。要了解如何向 TMP 暗示,在递归期间,每个实例将在递归期间拥有自己的 enum val = 1
副本,并且每个 val
将在其循环中具有适当的位置。正如@Kornel Kisielewicz 提到的那样,“枚举黑客”也受到旧编译器的支持,这些编译器禁止对static const
的初始值进行类内规范。
【讨论】:
【参考方案2】:与@Georg 的答案相反,当在专用模板中定义包含静态 const 变量的结构时,需要在源代码中声明它,以便链接器可以找到它并实际给它一个地址供参考。这可能会不必要地(取决于所需的效果)导致不优雅的代码,尤其是在您尝试创建仅标头库时。您可以通过将值转换为返回值的函数来解决它,这也可以打开模板以获取运行时信息。
【讨论】:
【参考方案3】:枚举不是 lval,静态成员值是,如果通过引用传递,模板将被实例化:
void f(const int&);
f(TMPFib<1>::value);
如果你想做纯粹的编译时间计算等,这是一个不受欢迎的副作用。
主要的历史差异是枚举也适用于不支持成员值的类内初始化的编译器,现在大多数编译器都应该修复这个问题。 enum 和 static const 之间的编译速度也可能存在差异。
在提升档案中的boost coding guidelines 和older thread 中有一些关于该主题的详细信息。
【讨论】:
我不知道它是否仍然是真的,通过查看编译器(godbolt)的输出,两个sn-ps产生相同的汇编代码。【参考方案4】:对于某些人来说,前者可能看起来不那么简单,而且更自然。如果您使用该类,它也会为自己分配内存,因此您可以例如获取 val 的地址。
一些较旧的编译器更好地支持后者。
【讨论】:
谢谢。正是我正在寻找的那种答案。 我个人完全不同意。然后枚举版本似乎更自然。为什么需要物理变量?枚举是常量值的表示。使用静态 const int 似乎更像是倒退到我们不得不使用宏来表示常量值的时代。 @Martin,关键字枚举和计算有什么关系?但重点是——每个人都可以对此有自己的看法。 @Martin - 老实说,我自己更喜欢使用枚举。 我也是一个枚举人。枚举本质上只是一个命名的积分常数,在这些情况下似乎很适合我们的需求。这是一个没有分配存储空间的右值。static const int
为它和所有东西分配了存储空间,这并不是必需的。以上是关于模板元编程 - 使用 Enum Hack 和 Static Const 的区别的主要内容,如果未能解决你的问题,请参考以下文章