C++ mark arithmetic hard-coded fraction as constexpr in a one-liner

92 Views Asked by At

I have a simple function that checks if a value is bigger than one third:

bool check(float x) {
   return x > 1.f/3;
}

Based on what I've read, the compilers will probably calculate the result of 1.f/3 at compile time to improve performance, but is not required to. To force him doing that, it's recommended to use:

bool check(float x) {
   constexpr float one_third = 1.f/3;
   return x > one_third;
}

My question is whether there is a way to do this as a one-liner, without having to define a separate expression. Something like:

bool check(float x) {
   return x > (constexpr float(1.f/3));
}

I could not find any way to do it and wanted to ask for confirmation. I found if-constexpr, but that requires both sides of the if to be constexpr, not just an internal subset of it. Lambda-constexpr or consteval could maybe work as oneliners?

4

There are 4 best solutions below

0
Jarod42 On BEST ANSWER

consteval lambda (C++20) might be used:

bool check(float x) {
   return x > []() consteval { return 1.f/3; }();
}

but I prefer the static constexpr variant for readability

bool check(float x) {
   static constexpr float one_third = 1.f/3;
   return x > one_third;
}
12
user12002570 On

whether there is a way to do this as a one-liner,

Yes, you can use a lambda and immediately invoke it:

bool constexpr check(float x) 
{
   return [x]()constexpr{return x>float(1.f/3);}(); 
}

Working demo

0
463035818_is_not_an_ai On

TL;DR: If you want to do it in one line / expression, your first version is totally fine.

Your question is based on the false premise that you would need to inform the compiler that 1.f/3 is a compile time constant. Though, the compiler knows that, you don't need to add a constexpr. Whoever recommended you to modify the initial version of the function didn't know what they were talking about. Thats the only explanation I can come up with. The constexpr does not add something useful. It does not open up opportunities for optimization that were not present in the original code. Also splitting it up into two lines does not affect optimizations.

If you ask gcc to optimize the codes it will produce identical output:

bool check1(float x) {
   return x > 1.f/3;
}

bool check2(float x) {
   constexpr float one_third = 1.f/3;
   return x > one_third;
}

Live:

check1(float):
        comiss  xmm0, DWORD PTR .LC0[rip]
        seta    al
        ret
check2(float):
        comiss  xmm0, DWORD PTR .LC0[rip]
        seta    al
        ret
.LC0:
        .long   1051372203

constexpr if is for compile time conditions, but x > 1.f/3; can only be evaluated at runtime.


It would be useful to declare 1.f/3 as constexpr when you want to use it in a context that requires a constant expression, for example:

 constexpr float x = 1.f/3;
 foobar<x>();               // use x as template argument

But thats not the case in the context of your function.

1
HolyBlackCat On

You're starting with a wrong premise.

All three major compilers (Clang, GCC, MSVC) generate worse assembly with constexpr variable when optimizations are disabled, and the same assembly when optimizations are enabled.

Here's Clang, for example: https://godbolt.org/z/qjvherx4v

Don't waste time worrying about microoptimizations on non-existent weird compilers.