原则上不可能C++进行严格的模板评估
Is strict template evaluation in principle impossible in C++?
我想我理解模板是如何懒惰地评估C++例如递归替换和扩展的最终简化。这通常会限制可用的递归深度。我想知道使用 C++11 中的新功能(例如可变参数模板或模板包)或一些 Boost 是否可以强制严格的模板评估。还是这在C++原则上是不可能的?
例如,考虑一个将所有整数值相加0..n
的模板:
template <int n>
struct sumAll { enum { value = n + sumAll<n-1>::value }; };
template <>
struct sumAll<0> { enum { value = 0 }; };
#include <iostream>
int main() { std::cout << sumAll<10000>::value << std::endl; }
在这里,sumAll<10>::value
将扩展到
sumAll<10>::value = 10 + sumAll<9>::value
= 10 + 9 + sumAll<8>::value
= 10 + 9 + 8 + sumAll<7>::value
= ...
= 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
只有在模板完全展开后,才会执行最终求和。如果最终扩展太长(例如,在具有许多项的复杂序列扩展中),编译器最终将耗尽空间来存储其他项。
我的问题本质上是是否有一种方法可以更早地进行简化(如上面的求和)。
您自己决定递归深度。就像普通递归会导致堆栈溢出一样,模板递归也可以。但这通常可以通过更好的递归算法来解决。微不足道:
template <int n>
struct sumAll { enum { value = n + n-1 + sumAll<n-2>::value }; };
template <>
struct sumAll<1> { enum { value = 0 }; };
template <>
struct sumAll<0> { enum { value = 0 }; };
聪明:
template <int n>
struct sumAll { enum { value = (n*n+2)/2; };
当然,你可能会抱怨后者只是愚蠢,真实的例子更复杂。但这难道不是问题的全部吗?编译器无法神奇地为您消除这种复杂性。
C++模板是图灵完备的,这意味着您可以使用它们在编译时评估每个可计算函数。然后从停止定理得出:
- 通常,您无法提前计算编译C++程序所需的内存量。 (即,没有可计算的函数将每个C++程序映射到绑定到其编译的内存)
- 通常,您无法决定编译器是完成实例化模板,还是将永远继续。
因此,虽然在某些情况下,您可以调整编译器以使用更少的内存,但有时无法解决内存不足的一般问题。
相关文章:
- C# HashSet VS C++ std::unordered_set 使用自定义类键。C++慢...不可能。如何实现 C# 的速度?
- 为什么在C++不可能递增或进行数学运算,例如在声明为数组的变量上乘法
- fopen 与常量字符 * 从 QString 是不可能的
- 矢量返回常量引用,不可能向下转换
- 分配取消引用的字符指针真的不可能吗?
- C#类过程 - 控制C 应用程序,不可能读取输出
- 可能是不可能的模板参数规范/推论
- 易失性结构 = 结构不可能,为什么?
- 矢量超出范围,将值分配给空矢量>不可能?
- 为什么不可能实例化原子对
- 一个倒梯形,但如果输入高度对于宽度来说太大,那么它应该报告,不可能("不可能的形状"是什么)
- W10上不可能使用十字架编译的libpng16-16.dll执行
- 如果明确给出多维数组,为什么不可能char [] [] [] = {..},{..}}
- 为什么我的自定义界面总是返回不可能的0x80040213/VFW_E_NO_CLOCK
- 从张量的读取设备不可能的方法
- 多态性抽象语法树(递归下降解析器):不可能
- IDXGISwapChain::CheckInterfaceSupport 返回一个不可能的结果
- C++为什么不可能将这两个操作合并在一行中?
- 指针将指针的指针等同于指针指向指针.不可能
- 原则上不可能C++进行严格的模板评估