C++11 - Static_Assert Within Constexpr Function

C++11 - static_assert within constexpr function?

This is not valid C++11 code, because a constexpr function must only contain a return statement.

This is incorrect. static_assert in a constexpr function are fine. What is not fine is using function parameters in constant expressions, like you do it.

You could throw if x <= 0. Calling the function in a context that requires a constant expression will then fail to compile

constexpr int do_something(int x) {
return x > 0 ? (x + 5) : (throw std::logic_error("x must be > 0"));
}

How to use static_assert for constexpr function arguments in C++?

assert works now that g++ has implemented N3652, Relaxing constraints on constexpr functions. This status page indicates that this has been implemented in gcc5.

assert also works (in constexpr functions) on the current clang compiler shipped by Apple, with -std=c++1y.

At this time, I see nothing in the standard that assures one that assert will work in constexpr functions, and such an assurance would be a welcome addition to the standard (at least by me).

Update

Richard Smith drew my attention to LWG 2234 submitted by Daniel Krügler which is attempting to create the assurance I refer to above.
This has been incorporated into C++17.

How to tell static_assert that constexpr function arguments are const?

Is there some simple way to tell the compiler that bar is always a compile time constant?

If bar is always compile-time constant, then you should write your function as:

template<int bar>
constexpr int foo()
{
static_assert(bar>arbitrary_number, "Use a lower number please");
return something_const;
}

Because if you don't do so, and instead write what you've already written, then in that case, the function can be called with non-const argument as well; it is just that when you pass non-const argument, then the function will loss it's constexpr-ness.

Note that in the above code arbitrary_number should be constant expression as well, or else it will not compile.

How to dispatch between assert() and static_assert(), dependend if in constexpr context?

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.

Is this use of static_assert inside if constexpr well-formed?

Both of your attempts (with the function and with the struct) are well-formed as is.

The other answer mentions [temp.res]/8, but I disagree with how it was interpreted.

The validity of a template may be checked prior to any instantiation. ... The program is ill-formed, no diagnostic required, if:

— no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or ...

Both the function and struct you wrote can be specialized to be true. I believe the mere possibility of specialization is enough, you don't actually need to add a dummy true specialization to make the code well-formed.

According to my understanding (and according to common sense, I hope), the point of this part of the standard is to allow compilers to check validity of templates and if constexpr branches early (when they are seen for the first time), and reject the ones that can't possibly be instantiated.

Every branch in your template can potentially be instantiated, because bool_value() can be specialized later. I doubt a sane compiler is going to reject your code due to bool_value() not being specialized yet.



Related Topics



Leave a reply



Submit