是基于constexpr的计算图灵完备

Is constexpr-based computation Turing complete?

本文关键字:计算 图灵完备 constexpr      更新时间:2023-10-16

我们知道C++模板元编程是图灵完备的,但预处理器元编程不是。

C++11为我们提供了一种新的元编程形式:constexpr函数的计算。这种形式的计算图灵是完整的吗?我在想,由于递归和条件运算符(?:)在constexpr函数中是允许的,这是可以的,但我希望有更专业的人来证实。

tl;dr:constexpr在C++11中并不完全是图灵的,这是由于语言规范中的一个错误,但这个错误已经在后来的标准草案中得到了解决,clang已经实现了修复。

ISO C++11国际标准中规定的constexpr不是图灵完备的。草图证明:

  • 每个constexpr函数f在特定参数序列a...上的结果(或非终止)仅由a...的值确定
  • 可以在常量表达式中构造的每个参数值都必须是文字类型,根据[basic.types]p10,文字类型为:
    • 标量类型
    • 参考
    • 文字类型的数组,或
    • 类类型
  • 上述每种情况都有一组有限的值。
    • 对于标量、非指针类型,下面将简单介绍
    • 对于要在常量表达式中使用的指针或引用,它必须由地址或引用常量表达式初始化,因此必须引用具有静态存储持续时间的对象,在任何程序中,该对象的数量都是有限的
    • 对于数组,绑定必须是一个常量,并且每个成员都必须由一个常量表达式初始化,然后得出结果
    • 对于类类型,有有限数量的成员,每个成员都必须是文字类型,并由常量表达式初始化,结果如下
  • 因此,f可以接收的可能输入a...的集合是有限的,因此任何有限描述的constexpr系统都是有限状态机,因此不是图灵完备的

然而,自从C++11标准发布以来,情况发生了变化。

Johannes Schaub对std::max()和std::min()not constexpr的回答中描述的问题作为核心问题1454报告给C++标准化委员会。在2012年2月的WG21会议上,我们决定这是标准中的一个缺陷,所选择的决议包括使用指定临时成员的指针或引用成员创建类类型值的能力。这允许constexpr函数累积和处理无界数量的信息,并且足以使constexpr评估图灵完成(假设实现支持递归到无界深度)。

为了证明constexpr对于实现核心问题1454的拟议解决方案的编译器的图灵完备性,我为clang的测试套件编写了一个图灵机模拟器:

https://github.com/llvm/llvm-project/blob/main/clang/test/SemaCXX/constexpr-turing.cpp

Clang 3.1和g++9以后的版本都在其C++11模式中实现了固定规则,并且可以处理该示例。

看看这些。我整理了这些例子,它们在GCC 4.6中起作用:编译时计算,编译时解析字符串-第一部分,编译时分析字符串-第二部分

如果我们考虑到真实计算机的限制,例如有限内存和MAX_INT的有限值,那么constexpr(以及整个C++)当然不是图灵完备的。

但如果我们去掉这个限制——例如,如果我们将int视为一个完全任意的正整数——那么是的,C++的constexpr部分将是图灵完备的。表示任何部分递归函数都很容易。

0,S(n)=n+1,选择器I_n^m(x_1,…,x_n)=x_m和叠加显然可以用constexpr表示。

基元递归可以直接完成:

constexpr int h(int x1, ..., int xn, int y) {
  return (xn == 0) ? f(x1, ..., xn) : g(x1, ..., xn, y-1, h(x1, ..., xn, y-1));
}

对于部分递归,我们需要一个简单的技巧:

constexpr int h(int x1, ... int xn, int y = 0) {
  return (f(x1, ... xn, y) == 0) ? y : h(x1, ..., xn, y+1);
}

因此,我们将任何部分递归函数作为constexpr。