C 如何处理递归类别的定义
How C++ handles recursive class definitions?
我最近开始使用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 如何处理这些递归定义?(资源)
或更具体地:
编译器如何处理包含枚举值的模板类的实例创建(在哪里/如何分配内存)?
编译后生成的所有类都保留在记忆中,还是由编译器优化,仅保留顶级类(清理)?
是否有一个独立的最大递归深度(由编译器本身构成的限制)?
关于此类结构的标准汇编的深入解释将得到高度赞赏。
pow::value
是编译时间中的常数表达式。编译器将通过计算A * pow<T, A, N - 1>::value
来计算pow<T, A, N>::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)
...
}
在这里,$0x100
是pow<int, 2, 8>::value
的结果。
编译器指定递归深度的最大深度。默认最大值为900。可以通过使用GCC中的-ftemplate-depth
开关来设置此值。
但是,-ftemplate-depth
值不得超过32位整数的最大值。
在上面的示例中,递归深度也可能受到type T
的限制。
int main() {
int result = pow<int, 2, 200>::value;
}
GCC会提醒
error: overflow in constant expression [-fpermissive]
- 此递归模板类型定义是否有效C++?
- 为什么当函数参数未定义为常量引用时存在无限递归?
- 通过 lambda 定义的 constexpr 递归函数
- 这是定义一组递归规则的正确方法吗?
- 具有全局定义变量的递归比没有全局定义变量的递归函数获得更多的堆栈.为什么?(跳入C++)
- 精神:不能在其规则定义中使用x3::skip(skipper)[一些递归规则]
- 共享指针中的递归,而变量在类中定义
- 如何定义递归概念
- 递归定义数组中的数据对齐和排序
- 递归std ::函数定义模板类方法
- 无限循环与无限递归.两者都未定义吗?
- 如何从非递归版本定义斐波那契函数
- C 递归类型定义
- 递归模板类别定义的基本案例要求
- 模拟递归定义的类似数组类的聚合初始化
- 递归中的锚点大小写定义
- 自然数(递归)的设定理论定义
- 如何用C++递归地从二进制文件中读取自定义字符串
- 使用带有使用constexpr递归定义的类型的C++11 initializer_list
- 从递归定义的类继承