For an embedded system, I've written a code that's generating a delay based on a compile-time and run-time selected variable. The compile-time version boils down to writting as much NOP instruction as required for reaching the expected CPU cycle count.
The main part is like this:
#define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__)
#define FORCE_INLINE __attribute__((always_inline))
template <int a> struct Nop {
__attribute__((always_inline)) static void nop() {
asm __volatile__("nop");
Nop<a-1>::nop();
}
};
template <> struct Nop<0> {
__attribute__((always_inline)) static void nop() {}
};
void bar(int x) {
// TODO: Make an asm version of this to avoid depending on compiler optimization
for (int i = 0; i < x; i++)
Nop<1>::nop();
}
template <bool e, int T> struct CTorRT
{
FORCE_INLINE CTorRT(int) {
if (T == 0) return;
if (T >= 40) bar(T - 10); // Switch to loop based delay now, since it's above the loop calling overhead
else Nop<T>::nop(); // Let's generate a bunch of nop!
}
};
template <int T> struct CTorRT<false, T>
{
FORCE_INLINE CTorRT(int v) { bar(v); }
};
#define DELAY_CYCLE(X) { CTorRT<IS_CONSTEXPR(X), IS_CONSTEXPR(X) ? X : 0> a(X); }
int main()
{
int d = 10;
[...]
DELAY_CYCLE(30); // Generates 30 NOP
DELAY_CYCLE(d); // Call bar(10) and loop 10 times over a single NOP loop
[...]
}
The code works as expected on all compilers (except for the oldest ones)
Yet, I've trouble understanding why it's not breaking on this part: CTorRT< A, A ? X : 0>
.
A
is a compile time constant (constexpr), yet X can be a dynamic variable, and as such, my understanding is that A ? X : 0
is not a constexpr (even if the result is obviously a constant expression in all cases).
What part of the standard implies that the expression: "constexpr_bool ? variable_or_constexpr : constexpr" is a constexpr ?