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
Related
I am just researching a three-way comparison operator <=>. I see that it returns std::strong_ordering. However, I fail to understand how the compiler is restricting only 0 in comparison operators (so<0, but not so<1)
#include<compare>
int main()
{
std::strong_ordering so = 55 <=> 10;
so < 0; // Fine
so < 1; // Fails
}
Similarly, so>20 won't work either. Following also won't work:
constexpr int Zero = 0;
so == Zero; // Error
so == 0; // Fine
EDIT - Interesting observation (on MSVC compiler). Following is valid:
so < nullptr
Using anything but a literal 0 to compare against std::strong_ordering is explicit undefined behavior, see [cmp.categories.pre]/3 of the C++20 draft.
It is up to the compiler/standard library how or whether this is enforced/diagnosed.
One way of achieving a diagnostic for the UB without any compiler magic is to use std::nullptr_t as argument to the overloaded comparison operator of std::strong_ordering (which has unspecified type according to the standard). Any integral zero literal can be implicitly converted to std::nullptr_t, but literals with other values or constant expressions that are not literals, cannot. See [conv.ptr]/1.
This is also mentioned in a draft note as possibility.
Libc++ seems to instead use a member pointer to some hidden class, see here.
Libstdc++ seems to do something similar, using a hidden class type that needs to be constructed from a pointer to itself, see here.
However neither of these implementations diagnose all arguments that result in UB according to the standard. In particular all of them also accept nullptr as argument without diagnostic: https://godbolt.org/z/esnvqR
I suppose full diagnosis of all the cases would require some compiler magic.
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.
Would you replace
const int one = 1;
const int two = 2;
with this?
constexpr int one = 1;
constexpr int two = 2;
Is my understanding correct that both blocks are semantically identical and that it is currently merely a matter of taste?
On the other hand, as constexpr implies const, you could argue that it is more consistent to always prefer the more restrictive form, even in trivial situations where it does not make a difference?
(I understand that the situation completely changes when the expression on the right side are allowed to be more complicated. So for clarification, the question only focuses on the most simple case where the expression is a fixed integer number.)
I think your statement saying that const and constexpr "are semantically identical" should be revised: they both declare objects whose value cannot change, but constexpr also requires the initializer expression to be computable at compile-time.
Now if the expression on the right-hand side cannot be computed at compile-time, using constexpr is out of the question. On the other hand, as long as the initializer is a literal, you could use constexpr, but keep into account what the semantics of your variable is: does your constant variable really represent something whose value should be computable at compile-time?
In a SW maintenance/evolution optics, it is possible that you will change the way you initialize your variable throughout time: today the initializer is a literal, tomorrow it might be a more complex expression.
Regardless of the way you are assigning it a value now, do you think that i will ever need to be initialized by anything else than a literal, and that the initializing expression may not be computable at compile-time? If that is the case, then just make your variable const, even though you are currently initializing it with a literal; otherwise, make it constexpr.
In other words, choose the qualifier that best expresses the semantics of your variable.
You don't have to replace const with constexpr in such case,
const int one = 1;
const int two = 2;
If you have a constant variable like this,
const int three = one + two;
you would better to define it as constexpr
constexpr int three = one + two;
to make sure three will be computed during the compilation period.
I know someone would argue, the modern compiler will do the optimizing, to even compute it just with const.
I just take an example for the usage of constexpr, the calculation maybe complicated and the compiler couldn't optimize it.
I'm not even sure if negative User-Defined Literals are allowed. If not, why were they left out?
For example, I would like to use:
auto money_i_owe_jack = -52_jpy;
This is what I tried using gcc 4.7.2:
constexpr int64_t operator "" _jpy(long long l)
{
return static_cast<int64_t>(l);
}
ERROR
Test_udl.cpp:60:47: error: ‘constexpr int64_t operator"" _jpy(long long int)’ has invalid argument list
Whether user-defined or otherwise, integer and floating point literals are always positive.
The reason is fairly simple: if you allow negative literals, lexing becomes context dependent. That is, when faced with something like - 10, the lexer can't just look at that text in isolation and know whether it should be treated as two separate tokens (- and 10) or one (-10). If you always treated it as a single token, then something like a - 10 would result in <a> and <-10> (i.e., <identifier><literal>, which isn't a legitimate sequence in C++ (or most other programming languages).
To get around that, the parser could feed some context to the lexer, telling at any given moment whether to expect (for example) an operator or an operand, so it would know that if it was to produce an operator, the - should be treated as a token of its own, but if an operand was expected, -10 would be a single token.
It's generally easier to have a single rule that's always followed though, and one that works is that the - is always an operator, and a literal can't include a - at all.
Integer literals need to be accepted as unsigned long long. The negative sign is not part of the literal, it is applied after the fact, to the returned value.
constexpr int64_t operator "" _jpy(unsigned long long l)
{
return static_cast<int64_t>(l);
}
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.