srinivirt
srinivirt

Reputation: 286

constexpr to return tuple of dimensions of a multidimensional C-style array

Is there a way to extend/modify/implement a constexpr to return a std::tuple of the dimensions of a multidimensional C-style array?

#include <iostream>
#include <tuple>
template<typename T, std::size_t N>
auto arraysize(T (&arr)[N])
{
    return std::make_tuple(N);
}

IOW, how to make arraysize to work for any-dimensional array? The above "works" but only returns one dimension:

int i[5];
std::cout << std::get<0>(arraysize(i)) << std::endl;

works, and returns 5. And,

char c[3][4];
std::cout << std::get<0>(arraysize(c)) << std::endl;

works, and returns 3, but

std::cout << std::get<1>(arraysize(c)) << std::endl;

doesn't compile because the arraysize() is not coded right. Is there a way to code it as a constexpr to handle any-dimensional array? Tried using parameter packs but was not successful.

Upvotes: 2

Views: 217

Answers (1)

Qaz
Qaz

Reputation: 61970

Use std::rank and std::extent with the index sequence trick: live example

#include <tuple>
#include <type_traits>
#include <utility>

template<typename Arr, std::size_t... Is>
constexpr auto extents_impl(const Arr&, std::index_sequence<Is...>) {
    return std::make_tuple(std::extent_v<Arr, Is>...);
}

template<typename Arr>
constexpr auto extents(const Arr& arr) {
    return extents_impl(arr, std::make_index_sequence<std::rank_v<Arr>>{});
}

These traits also return 0 for a non-array type or an array of unknown bound, leaving you with an empty tuple if your function is not given an array type. You can, of course, perform additional checking there if you wish.

Upvotes: 5

Related Questions