Like static_assert element size std :: array

I would like to be explicit about array size restrictions for a member variable so that other people don't accidentally make stupid changes. The following naive attempt will not compile:

struct Foo { std::array< int, 1024 > some_array; static_assert( (some_array.size() % 256) == 0, "Size must be multiple of 256" ); //^ (clang) error: invalid use of non-static data member 'some_array' }; 

Even if std::array::size is constexpr, I cannot directly use static_assert like this because neither the function nor my member variable are static.

The solution I came across is to use decltype (since I don't want to type an array) as follows:

 static_assert( (decltype(some_array)().size() % 256) == 0, "Size must be multiple of 256" ); 

It looks like it creates a rvalue value by default, which I thought was not constexpr.

Why does it work?

Is there a cleaner way to achieve a static statement?

+6
source share
2 answers

because neither the function nor my member variable are static.

Right The problem is that static assert cannot refer to a non-static member, because some_array.size() equivalent to this->some_array.size() , and there is no this pointer in the class scope (only inside function declarators and element initializers by default) .

However, it is okay to say decltype(array_size) , because in fact it is not trying to reference the array_size object or call its member functions, it just asks for the type of name declared in the class.

It looks like it creates a rvalue value by default, which I thought was not constexpr.

array<int, N> is a literal type, so it can be built in constant expressions. The fact that you are building an rvalue does not matter, you can build a literal and call the constexpr function on it in a constant expression.

It is impossible to use something like array<std::string, N> because std::string not a literal type and therefore is not array<string, N> .

Is there a cleaner way to achieve a static statement?

The standard flag std::tuple_size specialized for std::array so you can:

 static_assert( std::tuple_size<decltype(some_array)>::value % 256) == 0, "Size must be multiple of 256" ); 
+5
source

std::array::size is constexpr and should work with static_assert , however it does not work in this specific context (i.e. in the class definition), because some_array is a non-static member variable.

For this specific context, you can use a trait like home to take size at compile time, as shown below:

 template<typename> struct array_size; template<typename T, std::size_t N> struct array_size<std::array<T, N>> { static const std::size_t size = N; }; 

And static_assert like:

 static_assert(array_size<decltype(some_array)>::size % 256) == 0, "Size must be multiple of 256" ); 

Live demo

+7
source

All Articles