Is it possible to implement a thing such as "constexpr assert"
on bare metal?
I would normally use a throw
statement as it is mentioned here for example. But the compiler rejects the code because of --fno-exceptions
even though throw
is used only in a constant evaluated context.
My implementation:
inline constexpr void constexpr_assert(bool condition)
{
if (std::is_constant_evaluated())
{
if (!condition)
{
throw; // error: exception handling disabled, use '-fexceptions' to enable
}
}
else
{
assert(condition);
}
}
Potential usage:
class EventMask
{
uint32_t mask;
public:
static constexpr auto MAX_ID = 31;
constexpr EventMask(unsigned int event_id)
: mask(static_cast<uint32_t>(1u) << event_id)
{
constexpr_assert(event_id <= MAX_ID);
}
};
int main(int argc, char** argv)
{
EventMask s_ev(55); // this should fail on compilation time
EventMask d_ev(argc); // this could fail in the runtime
}
My compiler is (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1
CodePudding user response:
Since you know you're being constant evaluated, all you need to trigger a failure is to do something that's not valid to do during constant evaluation.
The easiest of these is to invoke a non-constexpr
function:
void on_error(char const* msg) {
// some code here... or not
}
Which you can then:
if (std::is_constant_evaluated())
{
if (!condition)
{
on_error("this is bad because of some reason that hopefully fits in a literal");
}
}
Obviously not the greatest solution, but at least you would get an error right here. gcc for instance gives a compile error like:
<source>:8:21: error: call to non-'constexpr' function 'void on_error(const char*)'
8 | on_error("bad!");
| ~~~~~~~~^~~~~~~~
Though I guess in this context, the string literal would come from the caller, and so it'd still show up in the call stack. Maybe then on_error()
should just take no parameters.