Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static_assert if expressions is constexpr

Tags:

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?

like image 928
RiaD Avatar asked May 19 '16 10:05

RiaD


People also ask

How do I know if a function 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.

What is_ static_ assert?

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.

Where to put static assert?

Unlike #error, assertion using static_assert takes place after the preprocessing translation stage.

Is constexpr implicitly static?

constexpr functions are implicitly inline , but not implicitly static .


2 Answers

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

like image 114
TartanLlama Avatar answered Oct 18 '22 12:10

TartanLlama


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 } 
like image 43
kennytm Avatar answered Oct 18 '22 10:10

kennytm