Most elegant way to write a one-shot 'if'
Use std::exchange
:
if (static bool do_once = true; std::exchange(do_once, false))
You can make it shorter reversing the truth value:
if (static bool do_once; !std::exchange(do_once, true))
But if you are using this a lot, don't be fancy and create a wrapper instead:
struct Once {
bool b = true;
explicit operator bool() { return std::exchange(b, false); }
};
And use it like:
if (static Once once; once)
The variable is not supposed to be referenced outside the condition, so the name does not buy us much. Taking inspiration from other languages like Python which give a special meaning to the _
identifier, we may write:
if (static Once _; _)
Further improvements: take advantage of the BSS section (@Deduplicator), avoid the memory write when we have already run (@ShadowRanger), and give a branch prediction hint if you are going to test many times (e.g. like in the question):
// GCC, Clang, icc only; use [[likely]] in C++20 instead
#define likely(x) __builtin_expect(!!(x), 1)
struct Once {
bool b = false;
explicit operator bool()
{
if (likely(b))
return false;
b = true;
return true;
}
};
Maybe not the most elegant solution and you don't see any actual if
, but the standard library actually covers this case:, see std::call_once
.
#include <mutex>
std::once_flag flag;
for (int i = 0; i < 10; ++i)
std::call_once(flag, [](){ std::puts("once\n"); });
The advantage here is that this is thread safe.
C++ does have a builtin control flow primitive that consists of "(before-block; condition; after-block)" already:
for (static bool b = true; b; b = false)
Or hackier, but shorter:
for (static bool b; !b; b = !b)
However, I think any of the techniques presented here should be used with care, as they are not (yet?) very common.
In C++17 you can write
if (static int i; i == 0 && (i = 1)){
in order to avoid playing around with i
in the loop body. i
starts with 0 (guaranteed by the standard), and the expression after the ;
sets i
to 1
the first time it is evaluated.
Note that in C++11 you could achieve the same with a lambda function
if ([]{static int i; return i == 0 && (i = 1);}()){
which also carries a slight advantage in that i
is not leaked into the loop body.