1

Can you have constexpr rvalues, e.g. when initializing variables using the result of several constexpr functions?

i.e. can I guarantee that an rvalue is computed at compile time regardless of compiler settings?


constexpr int getvalue1()
{
    return 42;
}

constexpr int getvalue2()
{
    return 24;
}

int main()
{


    // I want to initialize val with a value known at compile time
    constexpr int ceval  = getvalue1() + getvalue2();
    int val = ceval;

    // why can't I just do:
    // 
    // int val = constexpr getvalue1() + constexpr getvalue2();

}

https://godbolt.org/z/KcK23k

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
iwans
  • 445
  • 3
  • 13
  • Why do you think you cannot do the thing you think you cannot do? You can do it. – Cubic Mar 09 '20 at 12:03
  • @Cubic `int val = constexpr getvalue1() + constexpr getvalue2();` this line won't compile with: error: expected expression. – iwans Mar 09 '20 at 12:05
  • 3
    Yes, `getvalue1()` returns a `constexpr` rvalue. It may or may not be actually computed at compile-time. In release builds it probably will be computed at compile-time. Using a `constexpr` variable, like you did, should force it to be computed at compile-time regardless of compiler settings. In C++20 you can also use `consteval`. – HolyBlackCat Mar 09 '20 at 12:05
  • 3
    @iwans Why do you think it should compile? You can't just come up with some syntax and expect it to work. – HolyBlackCat Mar 09 '20 at 12:06
  • @HolyBlackCat I don't think it should compile, I'm asking if I can guarantee that a r-value will be computed at compile time regardless of compiler settings. – iwans Mar 09 '20 at 12:09
  • @iwans That's already _not_ what `constexpr` is about – Asteroids With Wings Mar 09 '20 at 12:11

2 Answers2

4

Just use:

int val = getvalue1() + getvalue2();

The optimizer will take care of it. If you disable the optimizer, then yes, the compiler will issue calls to these functions, otherwise you wouldn't be able to set breakpoints and step into them.

Even if you use C++20's consteval specifier which requires the functions to produce a constant expression, the compiler will still issue calls if you disable the optimizer:

consteval int getvalue1()
{ return 42; }

consteval int getvalue2()
{ return 24; }

// ...
int val = getvalue1() + getvalue2();

So long story short: just use the optimizer. If you force the issue the way you did through a intermediate constexpr variable, all you're doing is making debugging more difficult when you end up having to actually debug constexpr or consteval functions.

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
  • When looking at the generated assembly this creates two function calls. https://godbolt.org/z/dyRc_2 That's with optimizations turned off – iwans Mar 09 '20 at 12:07
  • 3
    @iwans That's because you didn't enable any optimization. Even with `-O1` you'll get compile-time values with no calls. – Nikos C. Mar 09 '20 at 12:08
  • @iwans `constexpr` doesn't mean "don't make function calls at runtime". That's not what it's for. All the compiler's usual "hmm should I inline or should I not inline" rules apply. – Asteroids With Wings Mar 09 '20 at 12:10
  • 3
    @iwans [ProTip] **always** turn on the optimizer when you want to see the assembly. Without optimizations turned on, a lot of the times you get literally what you wrote, which normally isn't optimal. – NathanOliver Mar 09 '20 at 12:10
  • @AsteroidsWithWings Yes, but can I force the compiler to compute it at compile time without relying on optimizations or assigning to a temporary? – iwans Mar 09 '20 at 12:12
  • 1
    @iwans `constexpr` only means that the value of the function call or variable _can_ be computed at compile time, not that it _must_. Doing so is in itself a form of compiler optimization (a rather fundamental one, and the main reason for `constexpr` to exist in the first place), it is not something that can be enforced or guaranteed, as per the standard. – jdehesa Mar 09 '20 at 12:14
  • @iwans No, the compiler is in charge of that. You can write the assembly manually if you wish ;) – Asteroids With Wings Mar 09 '20 at 13:44
2

With C++11 functionality, you can’t guarantee this, although most compilers will do this for such a simple case if you don’t turn optimisations off.

C++20 adds the constinit keyword for just this purpose, but this only works for static or thread-local variables.

Cubic
  • 14,902
  • 5
  • 47
  • 92