I want to create a class template
template <class T> class X { // here I'll use T::value (among other things) };
T::value
will often be a constexpr static variable, but not always. T::value
has to be positive value, so I want to let people know it during compilation, when possible.
If T::value
was always constexpr, I'd add static_assert
like
static_assert(T::value > 0, "need positive number");
Is it possible to add this static_assert only for cases when T::value
is constexpr?
The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.
The _Static_assert is a keyword defined in the C11 version of C. It evaluates a constant expression at compile-time and compares the result with 0. The _Static_assert is available as the macro static_assert keyword defined in C11. Click here for more information on static_assert.
Unlike #error, assertion using static_assert takes place after the preprocessing translation stage.
constexpr functions are implicitly inline , but not implicitly static .
We can write an is_valid
template function (come up with a better name) with two overloads:
template <typename T, int N = T::value> constexpr bool is_valid(int) { return N > 0; } template <typename T> constexpr bool is_valid(...) { return true; }
The first overload will only be valid if T::value
is a constant expression, otherwise it will be SFINAEd out. The second overload is valid no matter what, so we disambiguate the overload with a dummy int
parameter.
Now we test it like so:
static_assert(is_valid<T>(0), "need positive number");
Live Demo
This works for me on clang++:
#include <type_traits> // The default case, returns true if the value is not constant. template <typename T, typename = void> struct IsNonConstantOrPositive { static const bool value = true; }; // The `constexpr` case. We check if we can evaluate `T::value == 0` which can only // be evaluated at compile-time if `T::value` is constant. The whole `enable_if` thing // is to provide a substitution to ensure SFINAE. template <typename T> struct IsNonConstantOrPositive<T, typename std::enable_if<T::value==0||true>::type> { static const bool value = T::value > 0; }; template <typename T> struct X { static_assert(IsNonConstantOrPositive<T>::value, "T::value should be positive"); };
Example:
struct A { // const > 0, should succeed static const int value = 123; }; struct B { // const <= 0, should fail static const int value = -1234; }; struct C { // non-const, should succeed static int value; }; int main() { X<A> a; // ok //X<B> b; // error X<C> c; // ok }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With