mardi 4 septembre 2018

unpacking array extents at compile time (C++11/14)

I need to "pack" and "unpack" the dimensions of a multidimensional array at compile time. By "pack," I mean given a type which represents an array's dimensions such as

template<typename T, size_t N2, size_t N3> struct SomeType<T,0,0,N2,N3> { ... };

that I can extract a type T**[N2][N3] and perform the converse operation so that given a type T**[N2][N3], I can populate an index_sequence with parameters <0,0,N2,N3>

I've been able to perform the "pack" operation with the code:

/*   pack_array_type<T,N0>     is  T[N0]
 *   pack_array_type<T,0>      is  T*
 *   pack_array_type<T,N0,N1>  is  T[N0][N1]
 *   pack_array_type<T,0,N1>   is  T*[N1]
 *   pack_array_type<T,0,0>    is  T**
 *   etc                                  */

using namespace std;

template<typename,typename> struct pack_array_type_impl;

template<typename T, size_t N0, size_t...Ns>   
struct pack_array_type_impl<T,index_sequence<N0,Ns...>> {
  using type = typename 
  pack_array_type_impl<T[N0],index_sequence<Ns...>>::type;
};

template<typename T, size_t...Ns>
struct pack_array_type_impl<T,index_sequence<0,Ns...>> {
  using type = typename 
  pack_array_type_impl<T*,index_sequence<Ns...>>::type;
};

template<typename T, size_t N>
struct pack_array_type_impl<T,index_sequence<N>> { using type = T[N];};

template<typename T>
struct pack_array_type_impl<T,index_sequence<0>> { using type = T*; };

template<typename T, size_t...N>
using pack_array_type = typename 
pack_array_type_impl<T,index_sequence<N...>>::type;

My attempt at the inverse operation to "unpack" the dimensions is

template<typename, typename> struct unpacked_array_type_impl;

template<typename T, size_t...I>
struct unpacked_array_type_impl<T,index_sequence<I...>> {
  using index_type = index_sequence<extent<T[I]>::value...>;
};

template<typename T>
struct unpacked_array_type {
  using value_type = decay_t<T>;
  using index_type =
  typename unpacked_array_type_impl<T,make_index_sequence<rank<T>::value>>::type;
}

// Print indices for testing
void print_sequence( const index_sequence<N...>& seq, ostream& os ) {
  using expand_type = int[];
  os << "[";
  (void) expand_type
  { 0, ((void)(os << integral_constant<size_t,N>() << " ") , 0) ... };
  os << "]\n";
}

int main( int argc, char* argv[] ) {

  typename unpacked_array_type<double**[3][4][5]>::type x;
  // print_sequence(x,cout); // Desired output = [0 0 3 4 5 ]

  return 0;
}

Compiling with clang 5.0.1, gives the error main.cpp:54:12: error: implicit instantiation of undefined template 'unpacked_array_type_impl<double **[3][4][5], details::make_index_sequence<3> >' typename unpacked_array_type_impl<T,make_index_sequence<rank<T>::value>>::type; ^ main.cpp:68:12: note: in instantiation of template class 'unpacked_array_type<double **[3][4][5]>' requested here typename unpacked_array_type<double**[3][4][5]>::type x; ^ main.cpp:43:37: note: template is declared here template<typename, typename> struct unpacked_array_type_impl; ^ Is it possible to extract these dimensions?

Note: I am using my own implementation of some C++14 features such as index_sequence in C++11.

Aucun commentaire:

Enregistrer un commentaire