Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 261
ThePirate42 Avatar asked Apr 29 '21 21:04

ThePirate42


2 Answers

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.

like image 141
Brian Bi Avatar answered Sep 27 '22 15:09

Brian Bi


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.

like image 35
nielsen Avatar answered Sep 27 '22 15:09

nielsen