confusion about constexpr function body - c++

cppreference said the following about the body of a constexpr function:
the function body must not contain:
a definition of a variable of non-literal type
a definition of a variable of static or thread storage duration.
All I understood about a constexpr function is that the statements in its body should be evaluated at compile-time so that the call expression can be evaluated at compile-time. Am I true?
Since C++14, the standard allows the body to contain variable definitions of literal types. So what about those definitions, are they evaluated at compile-time or runtime? since non-constexpr variables are allowed also.
What I think I misunderstood is that the compiler shall be able to evaluate at compile-time every statement in a constexpr function body. Does this true since C++14?
To make my confusion clear, I have this simple example:
// assuming std::is_literal_type<T> is true.
constexpr T f() { T t{}; return t; };
I can't understand how the compile behaves with the above snippet. Variable t is an automatic non-const variable and gets defined at run-time not compile-time; so it basically cannot appear in a constexpr declaration. Does this means, the compiler will never evaluate f() at compile-time because it has a statement, that's T t;, which will be evaluated at runtime only.
My confusion is increased when I have tried:
constexpr T result = f();
and it compiles successfully!. Does this mean f() are evaluated at compile-time? if yes, what about the runtime definition of t?
My second question is about why static-duration variables are not allowed in the body of a constexpr function.

the statements in its body should be evaluated at compile-time
...along at least one possible code path.
Or, as the cpprefenrce page you're quoting puts it,
there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression
The function can be doing disk I/O if it wants to, as long as there is an if branch that skips it.
Variable t is ... defined at run-time not compile-time
It's defined in both. There is a run-time definition of the function (actual machine code compiled and written to the object file) and also there is a compile-time version of the function, a bunch of AST nodes or some sort of internal compiler representation of them. In a constexpr context, compile-time version will be evaluated and replaced by its result. In runtime context, a function call instruction will be compiled.

Related

Does the implicit conversion of a literal to a class type happen at compile time?

I'm trying to write a class that is closely related to integers, and because of that I included a conversion constructor with the form
constexpr example::example(const int &n);
My question is: if I subsequently define the function
void foo(example n);
and I use it like this
foo(3);
in my code, is the integer literal 3 converted in an instance of example at compile time?
If no, is there a way to obtain this behavior?
If yes, does that still happen if the constructor isn't explicitly declared as constexpr?
The fact that the constructor is constexpr does not force the computation to happen at compile time. It only means that the constructor is eligible to be used within both constant expressions and non-constant expressions.
If on the other hand you declare the constructor consteval, then it means that only constant expressions are allowed to call that constructor. This in turn implies that every invocation of the constructor must be checked by the compiler to ensure that it is a constant expression (because, if it is not, the compiler must diagnose the violation). Since checking that something is a constant expression requires checking whether it contains any undefined behaviour, such checking is as difficult as actually evaluating the expression. Therefore, you can be assured that declaring a constructor (or any other function) consteval will ensure that the function will not be called at runtime: the compiler is allowed to generate code to re-evaluate it at runtime, but there is no reason why it would do so. The downsides of this approach are that, first, it becomes impossible to use the constructor in a non-constant expression, and second, constant expression evaluation is much slower than runtime evaluation, and you have to decide whether the increased compile times are worth it.
If you leave the constructor as constexpr then you can still force it to be called at compile time in particular instances by using a constexpr variable:
constexpr example ex = 3; // evaluated at compile time
foo(ex);
This is a consequence of the fact that a constexpr variable is only allowed to be initialized by a constant expression.
In addition to the answer by Brian Bi, it should be mentioned that compiler optimization may cause the evaluation to happen at compile time in your example.
Look at this compilation without optimization https://godbolt.org/z/EccGosc7n versus the same code compiled with -O3: https://godbolt.org/z/Kz51x4acK.

constexpr member function of non constexpr constructible class

If a non-literal class type has no constexpr constructor (it is not constexpr constructible), does a non-static constexpr member function make any sense? I mean if you cannot construct the object at compile time, how would you able to use its member functions?
Anyway, the major compilers don't complain about it, which makes me think it is allowed by the standard.
Nevertheless, you are able to use such constexpr member functions in runtime without any problem. The only question now what is the effect of constexpr in this case, if any. My best guess is that the return value of the constexpr member is being evaluated at compile-time (if possible), so on a run-time call it have to do a simple copy.
Is my guess correct, or is the constexpr specifier absolutely meaningless in this case (i.e. the member function is being evaluated at runtime)?
The premise of your question seems to be that only constexpr functions can be evaluated at compile-time.
This premise is incorrect. The compiler can precompute anything it can figure out a way to do, as long as the exact side result and side-effects are produced (as-if rule).
What constexpr provides is a guarantee that certain expressions will be evaluated at compile-time by every compiler (it's not a "quality of implementation" issue), which makes it possible to use them in contexts where a compile-time value is needed, such as non-type template arguments, operands of case clauses in switch statements, etc.
The specific details around constexpr functions include that there has to be at least one set of arguments (the target instance is an implied argument) such that the constexpr evaluation rules are met. If that isn't true, your program is ill-formed and its runtime behavior is not specified at all, so don't go adding constexpr where it doesn't logically belong.
However, compilers aren't required to diagnose violations of this rule. That means that "major compilers don't complain about it" should not be in any way interpreted as assurance that the code is correct.
Standard's wording, section 7.1.5 (draft n4582)
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, or, for a constructor, a constant initializer for some object, the program is ill-formed; no diagnostic required.

Declaring constexpr functions or methods

I was wondering if there was any restrictions on where constexpr functions and methods have to be declared, like there are for inline functions and methods.
I know that inline functions or methods must be written in header files, to give the compiler access to their definition where they are called. It would make sense if there was something similar for constexpr, but I can't manage to find anything on that point...
So basically my questions are:
Can I write the definitions of constexpr functions in a header file without taking the risk of having a duplicate symbol?
Can I separate the declaration and definition of constexpr functions or methods?
The place you define a constexpr function affects how you can use it. In particular:
C++14[expr.const]p2:
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:
…
an invocation of an undefined constexpr function or an undefined constexpr constructor;
So you can't use a constexpr function in a constant expression (template argument, constexpr variable initializer, global variable initializer that needs to be evaluated statically, array bound expression, maybe others) if it's only been declared but not defined yet.
Similarly, as dyp commented,
C++14[dcl.constexpr]p2
… constexpr functions and constexpr constructors are implicitly inline (7.1.2).
That implies the answer to your first question: defining the constexpr function in a header won't cause duplicate symbols. It also means that if you declare a constexpr function in a header, and then call it in a translation unit, even only at runtime, "An inline function shall be defined in every translation unit in which it is odr-used." from C++14[basic.def.odr]p4.
Note that the rules for constant expressions and calls in general are different: calls in general require the definition to be somewhere in the translation unit: constant expressions require the definition to be before the constant expression.

Where in the C++11 standard does it specify when a constexpr function can be evaluated during translation?

Just because a function (or constructor)...
is declared constexpr and
the function definition meets the constexpr requirements
...doesn't mean that the compiler will evaluate the constexpr function during translation. I've been looking through the C++11 FDIS (N3242, available at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/) to try and determine two things:
When is the compiler obligated to evaluate a constexpr function during translation?
When is the compiler allowed to evaluate a constexpr function during translation?
Section 5.19 Paragraph 1 says that constant expressions can be evaluated during translation. As far as I can comprehend, the remainder of Section 5.19 sets forth the rules for what is valid in the definition of a constexpr function.
I understand that I can force constexpr evaluation during translation by declaring the result of the constexpr function as constexpr. Like this:
// Declaration
constexpr double eulers_num() { return 2.718281828459045235360287471; }
// Forced evaluation during translation
constexpr double twoEulers = eulers_num() * 2.0;
static_assert(twoEulers > 5.0, "Yipes!");
So far I've been unable to find the paragraphs in the FDIS that:
Force twoEulers to be evaluated during translation or
Specify other situations when the compiler may or must evaluate a constexpr function during translation.
What I'm particularly interested in discovering is whether constexpr evaluation during translation is triggered by:
When all parameters passed to the constexpr function are literals, or
The implied object argument during overload resolution (Section 13.3.1 Paragraph 3) is either constexpr or requires a literal (such as for array dimensions), or
Something else entirely.
Please, if possible, in your responses cite sections of the FDIS that I can look up or key phrases I can search in the FDIS. The English in the standard is somewhat obtuse, so I may have been reading the relevant paragraphs and have entirely missed their meaning or intent.
It is "allowed" to evaluate the constexpr call at compile time whenever it is actually possible to do so. Remember that the specification operates under the "as if" rule. So if you can't tell the difference, the compiler can do whatever it wants.
The compiler is required to evaluate constexpr calls at compile time when it actually needs the answer at compile time. For example:
constexpr int foo() {return 5;}
std::array<float, foo()> arr;
The compiler needs to know the array size at compile time. Therefore, it must evaluate the constant expression at compile time. If the constexpr function cannot be executed at compile time, you get a compile-time error.
Nicol Bolas is 100% correct, but there is one other interesting aspect: whether the expression is evaluated at translation-time and whether it is evaluated at run-time are completely independent questions. Since the constant expression cannot have side-effects, it can be evaluated an arbitrary number of times, and nothing stops it from being evaluated at both translation-time and run-time.
Suppose the constant expression were a large array (not a std::array, just an array), which is entirely legal, and the program does not indicate that it has static storage. Suppose also that only element 7 of the array is used in a context in which compile-time computation is necessary. It is quite reasonable for the compiler to compute the entire array, use element 7, discard it, and insert code to compute it at run-time in the scope in which it is used, rather than bloating the binary with the whole computed array. I believe this is not a theoretical issue; I've observed it with various compilers in various contexts. constexpr does not imply static.
Of course, if the compiler can determine that the array is not used at runtime, it might not even insert code to compute it, but that's yet another issue.
If you do use such an object at run-time, and you want to indicate to the compiler that it would be worth keeping it around for the duration of the program, you should declare it as static.
By combing the FDIS I have found three places that specify where a constexpr expression must be evaluated during translation.
Section 3.6.2 Initialization of non-local variables, paragraph 2 says if an object with static or thread local storage duration is initialized with a constexpr constructor then the constructor is evaluated during translation:
Constant initialization is performed:
if an object with static or thread storage duration is initialized by a constructor call, if the constructor is a constexpr constructor, if all constructor arguments are constant expressions (including conversions), and if, after function invocation substitution (7.1.5), every constructor call and full-expression in the mem-initializers is a constant expression;
Section 7.1.5 The constexpr specifier, paragraph 9 says if an object declaration includes the constexpr specifier, that object is evaluated during translation (i.e., is a literal):
A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, every full-expression that appears in its initializer shall be a constant expression. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression (5.19).
I’ve heard people argue that this paragraph leaves room for an implementation to postpone the initialization until runtime unless the effect can be detected during translation due to, say, a static_assert. That is probably not an accurate view because whether a value is initialized during translation is, under some circumstances, observable. This view is reinforced by Section 5.19 Constant expressions paragraph 4:
[ Note: Although in some contexts constant expressions must be evaluated during program translation, others may be evaluated during program execution. Since this International Standard imposes no restrictions on the accuracy of floating-point operations, it is unspecified whether the evaluation of a floating-point expression during translation yields the same result as the evaluation of the same expression (or the same operations on the same values) during program execution... — end note ]
Section 9.4.2 Static data members, paragraph 3 says if a const static data member of literal type is initialized by a constexpr function or constructor, then that function or constructor must be evaluated during translation:
If a static data member is of const literal type, its declaration in the class definition can specify a brace-orequal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ]
Interestingly, I did not find anything in the FDIS that required a constexpr expression to be evaluated if its result is used as an array dimension. I'm quite sure the standard committee expects that to be the case. But I also could have missed that in my search.
Outside of those circumstances the C++11 standard allows computations in constexpr functions and constructors to be performed during translation. But it does not require it. The computations could occur at runtime. Which computations the compiler performs during translation are, to a certain extent, a quality of implementation question.
In all three of the situations I located, the trigger for translation-time evaluation is based on the requirements of the target using the result of the constexpr call. Whether or not the arguments to the constexpr function are literal is never considered (although it is a pre-requisite for valid evaluation).
So, to get to the real point of this, it appears that constexpr evaluation during translation is triggered by:
The implied object argument during overload resolution (Section 13.3.1 Paragraph 3) is either constexpr or requires a literal.
I hope that's helpful to someone besides me. Thanks to everyone who contributed.
I don't think it's forced anywhere. I had a look too, it's tricky because there's not one paper on constexpr in that list; they all seem to add/remove from the previous collection of papers.
I think the general idea is when the inputs to the constexpr function are constexpr themselves, it'll all be done at compile time; and by extension non-function constexpr statements, which are literal anyway will be run at compile time if you're using a half intelligent compiler.
If a constexpr function or constructor is called with arguments which
aren't constant expressions, the call behaves as if the function were
not constexpr, and the resulting value is not a constant expression.
from wikipedia
which in seem to get the info from this pdf:
constexpr functions: A constexpr function is one which is “suf-
ficiently simple” so that it delivers a constant expression when
called with arguments that are constant values (see §2.1).

inline vs. constexpr?

With the new C++11 standard, when should I use the inline keyword over the constexpr keyword? Does the constexpr keyword offer any additional optimization over inline, or does it merely assert that things must be computed at compile-time?
Why does constexpr work on the GCC in some cases where the call is not constant, such as calling foo(x) on a non-constexpr variable? Is this a bug in the GCC or is it actually part of the standard?
Asserting that something can be computed at compile-time is a pretty strong kind of optimization.
Inlining merely removes a function call, by copy/pasting the function body into the call site. The function body still has to be executed, you just save the overhead of a function call.
But if you make the same code be evaluated at compile-time, it is free at runtime.
But neither inline nor constexpr are primarily about optimization. inline's main purpose is to suppress the one-definition-rule, so that functions can be defined in headers (which is useful for templates, and incidentally, also makes the inlining optimization easier)
And constexpr is there because it is useful in metaprogramming, and incidentally, it may help the compiler better optimize the code, by moving more computations to compile-time.
To quote wikipedia:
C++0x will introduce the keyword constexpr, which allows the user to
guarantee that a function or object constructor is a compile-time
constant.
Mark functions inline if they are super short. Mark functions as constexpr if the results are required at compile time. (Template parameters or array sizes). I believe a function can be both if needed.
A constant expression function or constructor can be called with
non-constexpr parameters. Just as a constexpr integer literal can be
assigned to a non-constexpr variable, so too can a constexpr function
be called with non-constexpr parameters, and the results stored in
non-constexpr variables. The keyword only allows for the possibility
of compile-time constancy when all members of an expression are
constexpr.
So, GCC is not incorrect in this.
While inline says to the compiler "This function is used somewhere in this translation unit and is not public to other object files", it is likely that the compiler inserts the body of the function into the caller. constexpr functions say to the compiler "This function has no side effects and does not depend on preconditions other than the parameter itsself."
constexpr variables just say "This variable does not change and its data can be included into the code.". However it makes a difference if you define a constexpr variable in a function static or nonstatic, eg. if a constexpr array is nonstatic, gcc just moves the data with hardcoded mov-instructions onto the stack, while static constexpr just stores the data in the .text-section.
Lambda expressions without capture assigned to a variable can be constexpr other than with capture, because without they need no memory to save the capture and they work like an empty class with overloaded operator() (but they can even be casted to plain function pointers with a simple unary plus: +[]{}).