c++ - C++ 如何处理递归类定义?

标签 c++ memory-management metaprogramming compiler-optimization compile-time

我最近开始使用 C++ 进行模板元编程,并一直在尝试将一些基本函数转换为它们各自的递归编译时模板定义。

例如:

template <typename T, T A, unsigned int N>
class pow { enum : T { value = A * pow<T, A, N-1>::value } };
template <typename T, T A> class pow<T, A, 0> { enum : T { value = 1 } };

模板的语法和强大功能令我惊叹。然而,有一个问题困扰着我: C++ 是如何处理这些递归定义的? (资源方面)

或者更具体地说:

  • 编译器如何处理包含枚举值的模板类的实例创建(在哪里/如何分配内存)?

  • 所有生成的类在编译后都保留在内存中,还是被编译器优化掉,只保留顶级类(清理)?

  • 是否存在独立于 RAM 的最大递归深度(编译器本身造成的限制)?

非常感谢有关此类结构的标准编译的深入解释。

最佳答案

pow::value是编译时的常量表达式。编译器将计算 pow<T, A, N>::value通过计算A * pow<T, A, N - 1>::value .文字 A在编译时也是一个const值,编译器会继续计算pow<T, A, N - 1>::value

...

计算pow<T, A, N - n>::value

计算pow<T, A, N - n - 1>::value

...

直到发现不需要计算时停止pow<T, A, 1>::value ,因为程序已经将 N = 1 的情况的值定义为 pow<T, A, 1>::value = 1

如果有人会写:

int main() {
    int value = pow<int, 1, -1>::value;
}

GCC 会提醒

fatal error: template instantiation depth exceeds maximum of xxx

那是因为编译器在达到最大递归深度之前找不到要解析的常量值。

编译后,编译器只会保留pow<T, A, N - n>::value的值作为immediate number而它不会存储编译期间解析的任何中间值。

int main() {
  400546:       55                      push   %rbp
  400547:       48 89 e5                mov    %rsp,%rbp
  ...
    int a = pow<int, 2, 8>::value;
  40055d:       c7 45 f0 00 01 00 00    movl   $0x100,-0x10(%rbp)
  ...
}

在这里,$0x100pow<int, 2, 8>::value 的结果.没有额外的地址保存这个结果。

递归深度的最大值由编译器指定。默认最大值为 900。可以使用 -ftemplate-depth 设置此值。在 GCC 中切换。

然而,-ftemplate-depth值不能超过 32 位整数的最大值。

在上面的例子中,递归深度也可能受限于type T。 .

int main() {
    int result = pow<int, 2, 200>::value;
}

GCC 会提醒

error: overflow in constant expression [-fpermissive]

关于c++ - C++ 如何处理递归类定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47972306/

相关文章:

objective-c - ARC 子类上的 super dealloc

ruby - 是否可以混合使用模块方法?

ruby-on-rails - 将模块/类中的代码注入(inject)到另一个模块/类中

c++ - C++ 中未对齐访问的正确性

windows - 进程的默认堆

c++ - 如何防止在 C++ 中无意中互换使用 delete 和 free?

ruby - 动态创建类方法

c++ - 可以像使用静态类函数那样使用派生类吗?

c++ - 构建wxWidgets Hello world

c++ - 线程杀死其父进程是否安全?