GCC is right. However, there is a relatively simple workaround:
#include "assert.h"
inline void assert_helper( bool test ) {
assert(test);
}
inline constexpr bool constexpr_assert( bool test ) {
return test?true:(assert_helper(test),false);
}
template<typename T> constexpr
inline T getClamped(const T& mValue, const T& mMin, const T& mMax)
{
return constexpr_assert(mMin < mMax), (mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue));
}
where we abuse the comma operator, twice.
The first time because we want to have an assert
that, when true
, can be called from a constexpr
function. The second, so we can chain two functions into a single constexpr
function.
As a side benefit, if the constexpr_assert
expression cannot be verified to be true
at compile time, then the getClamped
function is not constexpr
.
The assert_helper
exists because the contents of assert
are implementation defined when NDEBUG
is true, so we cannot embed it into an expression (it could be a statement, not an expression). It also guarantees that a failed constexpr_assert
fails to be constexpr
even if assert
is constexpr
(say, when NDEBUG
is false).
A downside to all of this is that your assert fires not at the line where the problem occurs, but 2 calls deeper.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…