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.
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.
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
If we take in account restrictions of real computer - such as finite memory and finite value of MAX_INT - then, of course, constexpr (and also the whole C++) is not Turing-complete.
But if we will remove this restriction - for example, if we will think about int as a completely arbitary positive integer - then yes, constexpr part of C++ will be Turing complete. It is easy to express any partial recursive function.
0, S(n) = n+1 and selectors I_n^m(x_1, ..., x_n) = x_m and superposition obviously can be expressed using constexpr.
Primitive recursion can be done it straight way:
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));
}
And for partial recursion we need a simple trick:
constexpr int h(int x1, ... int xn, int y = 0) {
return (f(x1, ... xn, y) == 0) ? y : h(x1, ..., xn, y+1);
}
So we get any partial recursion function as a constexpr.
Related
I've recently noticed the existence of types for complex values in C99 (after noticing their construction macros as a feature of C11).
Since this is C, these are built-in types, not structs with overloaded operators etc. But - is it or is it not the case that I can treat them as though they were based on C++'s std::complex template? i..e. is float _Complex effectively the same as std::complex<float> and double _Complex the same as std::complex<double>?
Note: Of course they have exactly the same behavior, since C++ has features which C doesn't, but think of it as though we restrict ourselves to the "C subset" except for these two types.
If they are not effectively the same - please explain how they differ.
std::complex is different from _Complex mainly in its interface.
To get real part of std::complex you use constexpr T real() const member function, the same for _Complex types requires creal macro.
So they are not the same type and it will be hard to pretend they are, but they do have the same internal layout.
C++17 29.5.4 states:
If z is an lvalue expression of type cv complex then:
the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,
reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and
reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.
Moreover, if a is an expression of type cv complex<T>* and the expression a[i] is well-defined for an integer expression i, then:
reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].
And C18 6.2.5.13 states:
Each complex type has the same representation and alignment
requirements as an array type containing exactly two elements of the
corresponding real type; the first element is equal to the real part,
and the second element to the imaginary part, of the complex number.
Which means you can use std::complex<T> and _Complex T to write interoperable code for C and C++.
Note: _Complex was introduced in C99.
According to cppreference section Core constant expressions point 19) a subtraction operator between two pointers is not legal constant expression until c++14. Can I assume that following code is legal c++17 code or is this interpretation an abuse?
int X, Y;
template <long long V>
struct S { };
int main() {
S<&X - &Y> s;
(void)s;
}
The question is moot. Pointer arithmetics is only defined on the pointers belonging to the same array, which is certainly not the case there. So, the code above is not legal C++, and in fact, fails to compile with compilers available to me.
The quoted cppref article says
A core constant expression is any expression that does not have any
one of the following ..
7) An expression whose evaluation leads to any form of core language
(since C++17) undefined behavior (including signed integer overflow,
division by zero, pointer arithmetic outside array bounds, etc).
Whether standard library undefined behavior is detected is
unspecified. (since C++17)
19) a subtraction operator between two pointers(until C++14)
Likely only array ptr arithemtics inside array bounds is getting 'legalized' since c++14, not all pointer arithmetics
Actually a demo shows that array ptr arithmetics compiles alright even with c++11 (not c++98)
I want to create a constexpr function that returns the endianness of the system, like so:
constexpr bool IsBigEndian()
{
constexpr int32_t one = 1;
return (reinterpret_cast<const int8_t&>(one) == 0);
}
Now, since the function will get executed at compile time rather than on the actual target machine, what guarantee does the C++ spec give to make sure that the correct result is returned?
None. In fact, the program is ill-formed. From [expr.const]:
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the
abstract machine (1.9), would evaluate one of the following expressions:
— [...]
— a reinterpret_cast.
— [...]
And, from [dcl.constexpr]:
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument
values exist such that an invocation of the function or constructor could be an evaluated subexpression of
a core constant expression (5.20), or, for a constructor, a constant initializer for some object (3.6.2), the
program is ill-formed; no diagnostic required.
The way to do this is just to hope that your compiler is nice enough to provide macros for the endianness of your machine. For instance, on gcc, I could use __BYTE_ORDER__:
constexpr bool IsBigEndian() {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return false;
#else
return true;
#endif
}
As stated by Barry, your code is not legal C++. However, even if you took away the constexpr part, it would still not be legal C++. Your code violates strict aliasing rules and therefore represents undefined behavior.
Indeed, there is no way in C++ to detect the endian-ness of an object without invoking undefined behavior. Casting it to a char* doesn't work, because the standard doesn't require big or little endian order. So while you could read the data through a byte, you would not be able to legally infer anything from that value.
And type punning through a union fails because you're not allowed to type pun through a union in C++ at all. And even if you did... again, C++ does not restrict implementations to big or little endian order.
So as far as C++ as a standard is concerned, there is no way to detect this, whether at compile-time or runtime.
I just learned this because of this question, that the standard states for std::complex (26.4 [complex.numbers]):
4 If z is an lvalue expression of type cv std::complex<T> then:
— the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,
— reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and
— reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.
Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i, then:
— reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
— reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].
This is something I really want to take advantage of in a standards-conforming manner. There are times when I have PODs, like mathematical vectors, which are composed of a single data type. Here are two example classes:
template <typename T, unsigned N>
struct Vector
{
T v[N];
};
template <typename T>
struct Quaternion
{
T r, i, j, k;
};
From what I understand, the implementation is allowed to add padding after the last member, as well as between members. Which means that sizeof(Quaterntion<float>) may not equal sizeof(float[4]), and sizeof(Vector<double, 8>) may not equal sizeof(double[8]). This means I typically have to add some static_asserts to my code to make sure that I can cast my Vector<float, N>/Quaterntion<float> to a float*, for example, and not worry about padding (for passing to C libraries or OpenGL buffers, for example).
Is there some method provided by the standard that would allow me to have the same guarantees for my little PODs, like Vector and Quaternion, as std::complex does? I'm aware of implementation-specific things, like __attribute__((packed)). I'm looking for for a non-implementation specific, standards conforming way of doing this. Since the standard requires support for this type of thing for implementations that provide std::complex, I'm wondering if there's also some standard way of applying this guarantee to my own classes.
I think you are asking the impossible.
Keep in mind that standard library implementors often rely on non-standard extensions or implementation-defined behavior. Indeed, in VC++'s complex header we find:
#pragma pack(push, _CRT_PACKING)
// implementation
#pragma pack(pop)
What you could do for your Quaternion is to place all the members inside an array, since the struct address can be reinterpret_cast to a pointer to the first member. But I guess that kind of defeats the purpose of the struct (direct member access by name).
It is not exactly what you ask for, but providing an
operator const T*() const // can be written in a portable manner
for your struct, will allow you to write
Quaternion<double> q = {};
const double * p = q;
at the cost of additional runtime/memory overhead, depending on how you implement the conversion operator.
I wonder, because predefined literals like ULL, f, etc. are obviously resolved at compile time. The standard (2.14.8 [lex.ext]) doesn't seem to define this, but it seems to tend towards runtime:
[2.14.8 / 2]
A user-defined-literal is treated as a call to a literal operator or literal operator template (13.5.8). To
determine the form of this call for a given user-defined-literal L with ud-suffix X, the literal-operator-id
whose literal suffix identifier is X is looked up in the context of L using the rules for unqualified name
lookup (3.4.1). Let S be the set of declarations found by this lookup. S shall not be empty.
(emphasis mine.)
However, to me this seems to introduce unnecessary runtime-overhead, as literals can only be appended to values that are available at compile-time anyways like 13.37f or "hello"_x (where _x is a user-defined-literal).
Then, we got the templated user-defined-literal, that never really gets defined in the standard AFAICS (i.e., no example is given, please prove me wrong). Is that function somehow magically invoked at compile time or is it still runtime?
Yes, you get a function call. But function calls can be compile time constant expressions because of constexpr literal operator functions.
For an example, see this one. As another example to show the advanced form of constexpr computations allowed by the FDIS, to have compile time base-26 literals you can do
typedef unsigned long long ull;
constexpr ull base26(char const *s, ull ps) {
return (*s && !(*s >= 'a' && *s <= 'z')) ? throw "bad char!" :
(!*s ? ps : base26(s + 1, (ps * 26ULL) + (*s - 'a')));
}
constexpr ull operator "" _26(char const *s, std::size_t len) {
return base26(s, 0);
}
Saying "bcd-"_26 will evaluate a throw-expression, and thereby cause the return value to become non-constant. In turn, it causes any use of "bcd-"_26 as a constant expression to become ill-formed, and any non-constant use to throw at runtime. The allowed form "bcd"_26 evaluates to a constant expression of the respective computed value.
Note that reading from string literals is not explicitly allowed by the FDIS, however it presents no problem and GCC supports this (the character lvalue reference is a constant expression and the character's value is known at compile time). IMO if one squints, one can read the FDIS as if this is allowed to do.
Then, we got the templated user-defined-literal, that never really gets defined in the standard AFAICS (i.e., no example is given, please prove me wrong)
The treatment of literals as invoking literal operator templates is defined in 2.14.8. You find more examples at 13.5.8 that detail on the literal operator function/function templates itself.
Is that function somehow magically invoked at compile time or is it still runtime?
The keyword is function invocation substitution. See 7.1.5.
#Johannes S is correct of course, but I'd like to add clearly (since I faced this), that even for constexpr user defined literals, the parameters are not considered constexpr or compile time constant, for example in the sense that they can not be used as integer constants for templates.
In addition, only things like this will actually give compile-time evaluation:
inline constexpr long long _xx(unsigned long long v) {
return (v > 100 ) ? throw std::exception() : v;
}
constexpr auto a= 150_xx;
So, that will not compile. But this will:
cout << 150_xx << endl;
And the following is not allowed:
inline constexpr long long _xx(unsigned long long v) {
return some_trait<v>::value;
}
That's annoying, but natural considering that (other) constexpr functions can be called also during execution.
Only for integer user-defined literals is it possible to force compile-time processing, by using the template form. Examples in my question and self answer: https://stackoverflow.com/a/13869688/1149664