Reputation: 1687
In C++11 it is possible to create a function which returns the size (number of elements) of a built-in one dimensional array at compile time using constexpr. Example below:
template <typename T, std::size_t N>
constexpr std::size_t size(T (&array)[N])
{
return N;
}
This is a superior alternative to ARRAY_SIZE and similar macros imo.
However, this will only return the size of the most significant dimension of a built-in multidimensional array.
I use the following function for determining the size of a built-in two dimensional array:
template <typename T, std::size_t N, std::size_t N2>
constexpr std::size_t size(T (&array)[N][N2])
{
return N * N2;
}
Ideally, it would be very useful to have a function that returns the size of a built-in array with an arbitrary number of dimensions. I thought variadic templates may help but I couldn't see a way of unpacking the template paramters as only one argument is passed. Is such a function possible?
Thanks in advance.
Upvotes: 4
Views: 1141
Reputation: 506897
template<typename T> constexpr int size(T const&) {
return 1;
}
template<typename T, int N> constexpr int size(T const (&a)[N]) {
return N * size(a[0]);
}
Upvotes: 3
Reputation: 523214
#include <type_traits>
#include <cstdlib>
template <typename T>
constexpr size_t size(const T&) noexcept
{
return sizeof(T)/sizeof(typename std::remove_all_extents<T>::type);
}
Example:
#include <cstdio>
int main()
{
int a[3][4][7][12];
char f[6];
printf("%lu == %ld ?\n", size(a), 3*4*7*12);
printf("%lu == %ld ?\n", size(f), 6);
return 0;
}
Upvotes: 5
Reputation: 137780
You're looking for std::extent
. C++11 §20.9.5:
template <class T, unsigned I = 0> struct extent;
If T is not an array type, or if it has rank less than or equal to I, or if I is 0 and T has type “array of unknown bound of U”, then 0; otherwise, the bound (8.3.4) of the I’th dimension of T, where indexing of I is zero-based.
Usage, also from the Standard, prefix extent
with std::
as needed:
assert((extent<int[2][4], 1>::value) == 4);
You should also probably use this to replace your custom size
function.
Edit: Oops, now I read to the end of the question :vP . You also need std::remove_extent
.
template< typename multi_array, bool = std::is_array< multi_array >::value >
struct total_extent;
template< typename multi_array >
struct total_extent< multi_array, false > {
enum { value = 1 };
};
template< typename multi_array >
struct total_extent< multi_array, true > {
enum {
value = std::extent< multi_array >::value
* total_extent< typename std::remove_extent< multi_array >
::type >::value
};
};
Upvotes: 2