【发布时间】:2021-04-29 22:05:29
【问题描述】:
我正在阅读 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); 书中说:
编译器必须传递 Pow3::value 的地址,这会强制 编译器实例化和分配静态成员的定义。因此, 计算不再局限于纯粹的“编译时”效果。枚举值不是左值(即它们没有地址)。所以,当我们 通过引用传递它们,不使用静态内存。几乎就像你通过了 计算值作为文字。
说实话,我完全不明白他们的解释。我认为在静态常量版本中,我们在编译时评估结果,但实际引用发生在运行时,因为我们需要传递地址。但是我看不到前一种情况(枚举实现)有太大区别,因为我们应该在那里有临时物化(prvalue -> xvalue 转换),并且由于临时对象也有地址,所以我的思考过程失败了。它还说“不使用静态内存”,我也不明白,因为静态内存应该指的是在编译时发生的分配。
有人可以更详细地解释整个事情吗?
【问题讨论】:
-
静态成员具有链接时效果:您将获得变量的符号,链接器必须处理它。另一方面,临时变量与链接器完全无关。
-
从另一个角度来看,对象在其生命周期中通常具有不同的地址。静态变量具有静态存储持续时间(= 进程/库的生命周期)。因此,它们的生命周期由可执行文件中的 .. 静态条目维护(如果它们没有被优化删除)。
标签: c++ template-meta-programming