Info
-
Did you know about
std::rank/std::rank_v
type_trait to get the rank of the array?
Example
static_assert(0 == std::rank_v<void>);
static_assert(0 == std::rank_v<int>);
static_assert(1 == std::rank_v<int[]>);
static_assert(0 == std::rank_v<int[0]>);
static_assert(1 == std::rank_v<int[1]>);
static_assert(1 == std::rank_v<int[42]>);
static_assert(2 == std::rank_v<int[][2]>);
static_assert(2 == std::rank_v<int[1][2]>);
static_assert(3 == std::rank_v<int[1][2][3]>);
Puzzle
Can you implement standard compliant version of
std::rank_v
?
static_assert(0 == rank_v<void>);
static_assert(0 == rank_v<int>);
static_assert(1 == rank_v<int[]>);
static_assert(0 == rank_v<int[0]>);
static_assert(1 == rank_v<int[1]>);
static_assert(1 == rank_v<int[42]>);
static_assert(2 == rank_v<int[][2]>);
static_assert(2 == rank_v<int[1][2]>);
static_assert(3 == rank_v<int[1][2][3]>);
Solutions
#include <type_traits>
template<class T>
struct prev;
template<class T, int N>
struct prev<T[N]> : std::type_identity<T> {};
template<class T>
struct prev<T[]> : std::type_identity<T> {};
template<class T>
constexpr auto return_rank()
{
if constexpr (::std::is_array_v<T>) {
return return_rank<typename prev<T>::type>() + 1;
}
return 0;
}
template<class T>
constexpr auto rank_v = return_rank<T>();
namespace detail {
template <typename T>
constexpr auto rank(){
if constexpr (std::is_array_v<T>) {
return 1 + rank<std::remove_extent_t<T>>();
} else {
return 0;
}
}
};
template <typename T>
constexpr auto rank_v = detail::rank<T>();
template<class T>
struct rank : public std::integral_constant<std::size_t, 0> {};
template<class T>
struct rank<T[]> : public std::integral_constant<std::size_t, rank<T>::value + 1> {};
template<class T, std::size_t N>
struct rank<T[N]> : public std::integral_constant<std::size_t, rank<T>::value + 1> {};
template< class T >
inline constexpr std::size_t rank_v = rank<T>::value;
template <class>
constexpr auto rank_v = 0uz;
template <class T>
constexpr auto rank_v<T[]> = rank_v<T> + 1uz;
template <class T, auto N>
constexpr auto rank_v<T[N]> = rank_v<T[]>;
template<typename T>
constexpr auto rank_v = []{
constexpr auto recur = []<typename U>(auto recur, std::type_identity<U>, auto accum){
if constexpr (std::is_array_v<U>){
return recur(recur, std::type_identity<std::remove_extent_t<U>>{}, accum+1);
} else {
return accum;
}
};
return recur(recur, std::type_identity<T>{}, 0);
}();