In C++11 constexpr functions, a second statement such as an assert()
is not possible. A static_assert()
is fine, but wouldn't work if the function is called as 'normal' function. The comma operator could come to help wrto. the assert()
, but is ugly and some tools spit warnings about it.
Consider such 'getter' which is perfectly constexpr-able beside the assertion. But I would like to keep some kind of assertion for runtime and compile time, but cannot just overload depending on the 'constexpr' context.
template<int Size>
struct Array {
int m_vals[Size];
constexpr const int& getElement( int idx ) const
{
ASSERT( idx < Size ); // a no-go for constexpr funcs in c++11
// not possible, even in constexpr calls as being pointed out, but what I would like:
static_assert( idx < Size, "out-of-bounds" );
return m_vals[idx];
}
};
Side conditions: C++11, no heap, no exceptions, no compiler specifics.
Note as commenters pointed out (thanks!), static_assert
on the argument is not possible (but would be nice). The compiler gave me a different error on out-of-bounds access in that situation.
Something like
void assert_impl() { assert(false); } // Replace body with own implementation
#ifdef NDEBUG // Replace with own conditional
#define my_assert(condition) ((void)0)
#else
#define my_assert(condition) ((condition) ? (void()) : (assert_impl(), void()))
#endif
template<int Size>
struct Array {
int m_vals[Size];
constexpr const int& getElement( int idx ) const
{
return my_assert(idx < Size), m_vals[idx];
}
};
It will give a compile time error on assertion failure if used in a context requiring a constant expression (because it will call a non-constexpr
function).
Otherwise it will fail at runtime with a call to assert
(or your analogue).
This is the best that you can do as far as I know. There is no way to use the value of idx
to force a check at compile-time outside of context requiring constant expressions.
The comma operator syntax is not nice, but C++11 constexpr
functions are very limited.
Of course, as you already noted, undefined behavior will be diagnosed anyway if the function is used in a context requiring a constant expression.
If you know that assert
(or your analogue) doesn't expand to anything that is forbidden in a constant expression if the condition evaluates to true
but does so if it evaluates to false
, then you can use it directly instead of my_assert
and skip the indirection that I build in my code.