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

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.

Related

confusion about constexpr function body

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.

Is constexpr really needed in c++ in general? [duplicate]

C++11 allows functions declared with the constexpr specifier to be used in constant expressions such as template arguments. There are stringent requirements about what is allowed to be constexpr; essentially such a function encapsulates only one subexpression and nothing else. (Edit: this is relaxed in C++14 but the question stands.)
Why require the keyword at all? What is gained?
It does help in revealing the intent of an interface, but it doesn't validate that intent, by guaranteeing that a function is usable in constant expressions. After writing a constexpr function, a programmer must still:
Write a test case or otherwise ensure it's actually used in a constant expression.
Document what parameter values are valid in a constant expression context.
Contrary to revealing intent, decorating functions with constexpr may add a false sense of security since tangential syntactic constraints are checked while ignoring the central semantic constraint.
In short: Would there be any undesirable effect on the language if constexpr in function declarations were merely optional? Or would there be any effect at all on any valid program?
Preventing client code expecting more than you're promising
Say I'm writing a library and have a function in there that currently returns a constant:
awesome_lib.hpp:
inline int f() { return 4; }
If constexpr wasn't required, you - as the author of client code - might go away and do something like this:
client_app.cpp:
#include <awesome_lib.hpp>
#include <array>
std::array<int, f()> my_array; // needs CT template arg
int my_c_array[f()]; // needs CT array dimension
Then should I change f() to say return the value from a config file, your client code would break, but I'd have no idea that I'd risked breaking your code. Indeed, it might be only when you have some production issue and go to recompile that you find this additional issue frustrating your rebuilding.
By changing only the implementation of f(), I'd have effectively changed the usage that could be made of the interface.
Instead, C++11 onwards provide constexpr so I can denote that client code can have a reasonable expectation of the function remaining a constexpr, and use it as such. I'm aware of and endorsing such usage as part of my interface. Just as in C++03, the compiler continues to guarantee client code isn't built to depend on other non-constexpr functions to prevent the "unwanted/unknown dependency" scenario above; that's more than documentation - it's compile time enforcement.
It's noteworthy that this continues the C++ trend of offering better alternatives for traditional uses of preprocessor macros (consider #define F 4, and how the client programmer knows whether the lib programmer considers it fair game to change to say #define F config["f"]), with their well-known "evils" such as being outside the language's namespace/class scoping system.
Why isn't there a diagnostic for "obviously" never-const functions?
I think the confusion here is due to constexpr not proactively ensuring there is any set of arguments for which the result is actually compile-time const: rather, it requires the programmer to take responsibility for that (otherwise §7.1.5/5 in the Standard deems the program ill-formed but doesn't require the compiler to issue a diagnostic). Yes, that's unfortunate, but it doesn't remove the above utility of constexpr.
So, perhaps it's helpful to switch from the question "what's the point of constexpr" to consider "why can I compile a constexpr function that can never actually return a const value?".
Answer: because there'd be a need for exhaustive branch analysis that could involve any number of combinations. It could be excessively costly in compile time and/or memory - even beyond the capability of any imaginable hardware - to diagnose. Further, even when it is practical having to diagnose such cases accurately is a whole new can of worms for compiler writers (who have better uses for their time). There would also be implications for the program such as the definition of functions called from within the constexpr function needing to be visible when the validation was performed (and functions that function calls etc.).
Meanwhile, lack of constexpr continues to forbid use as a const value: the strictness is on the sans-constexpr side. That's useful as illustrated above.
Comparison with non-`const` member functions
constexpr prevents int x[f()] while lack of const prevents const X x; x.f(); - they're both ensuring client code doesn't hardcode unwanted dependency
in both cases, you wouldn't want the compiler to determine const[expr]-ness automatically:
you wouldn't want client code to call a member function on a const object when you can already anticipate that function will evolve to modify the observable value, breaking the client code
you wouldn't want a value used as a template parameter or array dimension if you already anticipated it later being determined at runtime
they differ in that the compiler enforces const use of other members within a const member function, but does not enforce a compile-time constant result with constexpr (due to practical compiler limitations)
When I pressed Richard Smith, a Clang author, he explained:
The constexpr keyword does have utility.
It affects when a function template specialization is instantiated (constexpr function template specializations may need to be instantiated if they're called in unevaluated contexts; the same is not true for non-constexpr functions since a call to one can never be part of a constant expression). If we removed the meaning of the keyword, we'd have to instantiate a bunch more specializations early, just in case the call happens to be a constant expression.
It reduces compilation time, by limiting the set of function calls that implementations are required to try evaluating during translation. (This matters for contexts where implementations are required to try constant expression evaluation, but it's not an error if such evaluation fails -- in particular, the initializers of objects of static storage duration.)
This all didn't seem convincing at first, but if you work through the details, things do unravel without constexpr. A function need not be instantiated until it is ODR-used, which essentially means used at runtime. What is special about constexpr functions is that they can violate this rule and require instantiation anyway.
Function instantiation is a recursive procedure. Instantiating a function results in instantiation of the functions and classes it uses, regardless of the arguments to any particular call.
If something went wrong while instantiating this dependency tree (potentially at significant expense), it would be difficult to swallow the error. Furthermore, class template instantiation can have runtime side-effects.
Given an argument-dependent compile-time function call in a function signature, overload resolution may incur instantiation of function definitions merely auxiliary to the ones in the overload set, including the functions that don't even get called. Such instantiations may have side effects including ill-formedness and runtime behavior.
It's a corner case to be sure, but bad things can happen if you don't require people to opt-in to constexpr functions.
We can live without constexpr, but in certain cases it makes the code easier and intuitive.
For example we have a class which declares an array with some reference length:
template<typename T, size_t SIZE>
struct MyArray
{
T a[SIZE];
};
Conventionally you might declare MyArray as:
int a1[100];
MyArray<decltype(*a1), sizeof(a1)/sizeof(decltype(a1[0]))> obj;
Now see how it goes with constexpr:
template<typename T, size_t SIZE>
constexpr
size_t getSize (const T (&a)[SIZE]) { return SIZE; }
int a1[100];
MyArray<decltype(*a1), getSize(a1)> obj;
In short, any function (e.g. getSize(a1)) can be used as template argument only if the compiler recognizes it as constexpr.
constexpr is also used to check the negative logic. It ensures that a given object is at compile time. Here is the reference link e.g.
int i = 5;
const int j = i; // ok, but `j` is not at compile time
constexprt int k = i; // error
Without the keyword, the compiler cannot diagnose mistakes. The compiler would not be able to tell you that the function is an invalid syntactically as aconstexpr. Although you said this provides a "false sense of security", I believe it is better to pick up these errors as early as possible.

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.

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: +[]{}).