我正在阅读《C++ 模板:完整指南》第 23 章“元编程”。最后,它描述了 在元编程中使用枚举值与静态常量的区别。考虑以下两种计算 3 的 N 次方的实现:
枚举实现:
// primary template to compute 3 to the Nth
template<int N>
struct Pow3 {
enum { value = 3 * Pow3<N-1>::value };
};
// full specialization to end the recursion
template<>
struct Pow3<0> {
enum { value = 1 };
};
静态常量实现:
// primary template to compute 3 to the Nth
template<int N>
struct Pow3 {
static int const value = 3 * Pow3<N-1>::value;
};
// full specialization to end the recursion
template<>
struct Pow3<0> {
static int const value = 1;
};
紧接着它说后一个版本有一个缺点。如果我们有一个函数
void foo(int const&);
并将元程序的结果传递给它:foo(Pow3<7>::value);
书上说:
A compiler must pass the address of Pow3<7>::value, and that forces the compiler to instantiate and allocate the definition for the static member. As a result, the computation is no longer limited to a pure “compile-time” effect. Enumeration values aren’t lvalues (i.e., they don’t have an address). So, when we pass them by reference, no static memory is used. It’s almost exactly as if you passed the computed value as a literal.
说实话,我根本不明白他们的解释。我认为在静态常量版本中,我们在编译时评估结果,但实际引用发生在运行时,因为我们需要传递地址。但是我在前一种情况(枚举实现)中没有看到太大的区别,因为我们应该在那里进行临时物化(prvalue -> xvalue 转换),并且由于临时对象也有地址,所以我的思考过程失败了。它还说“不使用静态内存”,我也不明白,因为静态内存应该指的是编译时发生的分配。
有人可以更详细地解释整个事情吗?
最佳答案
(enum implementation) because we should have temporary materialization there (prvalue -> xvalue conversion) and since temporary objects also have the address
确实如此,但临时 xvalue 仅在函数调用期间存在。它与向函数传递整数文字相同。因此,可寻址对象在运行时临时存在,具有自 Action 用域。
相反,
... that forces the compiler to instantiate and allocate the definition for the static member. As a result, the computation is no longer limited to a pure “compile-time” effect.
这个static const int
是一个带有 static
的对象储存期限。不需要临时物化,它是一个对象,在程序启动时就存在,并且您正在引用它。
如果您编写多个 .cpp 文件,其中包括带有 Pow3
的 header ,他们都打电话 foo(Pow3<3>)
:
enum
版本将发出类似foo(27)
的内容在每个翻译单元中,具有三个不相关的临时 xvaluestatic
version 将发出一个相当于const int Pow3<3>::value = 27;
的全局对象并且每个翻译单元都会引用(即引用)同一个对象
关于c++ - 元编程中的枚举值与静态常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67317324/