基于constexpr的计算图灵完成了吗?

时间:2012-02-08 21:13:17

标签: c++ c++11 metaprogramming computation-theory constexpr

我们知道C++ template metaprogramming is Turing complete,但preprocessor metaprogramming is not

C ++ 11为我们提供了一种新形式的元编程:constexpr函数的计算。这种计算形式是图灵完备吗?我在想,因为在constexpr函数中允许使用递归和条件运算符(?:),但是我希望有更多专业知识的人来确认。

3 个答案:

答案 0 :(得分:55)

由于语言规范中存在一个错误,C ++ 11中的

tl; dr:constexpr并不是图灵完备的,但该错误已在后来的标准草案中得到解决,并且已经铿锵作响实现修复。

按照ISO C ++ 11国际标准的规定,

constexpr不是图灵完备的。草图证明:

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

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

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

为了演示实现核心问题1454的解决方案的编译器的constexpr的图灵完整性,我为clang的测试套件编写了图灵机模拟器:

http://llvm.org/svn/llvm-project/cfe/trunk/test/SemaCXX/constexpr-turing.cpp

g ++和clang的中继版本实现了这个核心问题的解决方案,但是g ++的实现目前无法处理这个代码。

答案 1 :(得分:7)

看看这些。我编译了这些示例,它们在GCC 4.6中工作: Compile-time computationsParsing strings at compile-time - Part IParsing strings at compile-time - Part II

答案 2 :(得分:1)

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

但是如果我们将删除这个限制 - 例如,如果我们将int视为一个完全正则的正整数 - 那么是的,constexpr C ++的一部分将是Turing完成的。表达任何部分递归函数都很容易。

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。