Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is constexpr-based computation Turing complete?

We know that C++ template metaprogramming is Turing complete, but preprocessor metaprogramming is not.

C++11 gives us a new form of metaprogramming: computation of constexpr functions. Is this form of computation Turing-complete? I am thinking that since recursion and the conditional operator (?:) are allowed in constexpr functions, it would be, but I would like someone with more expertise to confirm.

like image 282
HighCommander4 Avatar asked Feb 08 '12 21:02

HighCommander4


People also ask

Is template metaprogramming Turing-complete?

Template metaprogramming is Turing-complete, meaning that any computation expressible by a computer program can be computed, in some form, by a template metaprogram. Templates are different from macros.

Are constexpr functions evaluated at compile time?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

Is the preprocessor Turing-complete?

the preprocessor is not Turing complete, at least not if the program is preprocessed only once. This is true even if the program is allowed to include itself.

What is the point of constexpr functions?

constexpr functions A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.


2 Answers

tl;dr: constexpr in C++11 was not Turing-complete, due to a bug in the specification of the language, but that bug has been addressed in later drafts of the standard, and clang already implements the fix.

constexpr, as specified in the ISO C++11 international standard, is not Turing-complete. Sketch proof:

  • Every constexpr function f's result (or non-termination) on a particular sequence of arguments, a..., is determined only by the values of a...
  • Every argument value that can be constructed inside a constant expression must be of a literal type, which by [basic.types]p10 is either:
    • a scalar type,
    • a reference,
    • an array of literal type, or
    • a class type
  • Each of the above cases has a finite set of values.
    • For a scalar, non-pointer type, this follows trivially.
    • For a pointer or reference to be used in a constant expression, it must be initialized by an address or reference constant expression, so must refer to an object with static storage duration, of which there are only a finite quantity in any program.
    • For an array, the bound must be a constant, and each member must be initialized by a constant expression, from which the result follows.
    • For a class type, there are a finite number of members, and each member must be of literal type and initialized by a constant expression, from which the result follows.
  • Therefore, the set of possible inputs a... which f can receive is finite, so any finitely-described constexpr system is a finite state machine, and thus is not Turing-complete.

However, since the publication of the C++11 standard, the situation has changed.

The problem described in Johannes Schaub's answer to std::max() and std::min() not constexpr was reported to the C++ standardization committee as core issue 1454. At the February 2012 WG21 meeting, we decided that this was a defect in the standard, and the chosen resolution included the ability to create values of class types with pointer or reference members that designate temporaries. This allows an unbounded quantity of information to be accumulated and processed by a constexpr function, and is sufficient to make constexpr evaluation Turing-complete (assuming that the implementation supports recursion to an unbounded depth).

In order to demonstrate the Turing-completeness of constexpr for a compiler that implements the proposed resolution of core issue 1454, I wrote a Turing-machine simulator for clang's test suite:

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

Trunk versions of both g++ and clang implement the resolution of this core issue, but g++'s implementation currently is unable to process this code.

like image 72
Richard Smith Avatar answered Sep 24 '22 12:09

Richard Smith


Have a look at these. I compiled the examples and they work in GCC 4.6: Compile-time computations, Parsing strings at compile-time - Part I, Parsing strings at compile-time - Part II

like image 43
Andrzej Avatar answered Sep 23 '22 12:09

Andrzej