我需要在编译时“打包”和“解包”多维C风格数组的维度。通过“pack”,我的意思是给出一个表示数组维度的类型,例如
template<typename T, size_t N2, size_t N3>
struct SomeType<T,0,0,N2,N3> { ... };
我可以提取一个类型T**[N2][N3]
并执行逆向操作,以便给定一个类型T**[N2][N3]
,我可以用参数std::index_sequence
填充<0,0,N2,N3>
我已经能够使用代码执行“打包”操作:
/* 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;
我尝试逆向操作“解包”尺寸是
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>;
// EDIT: Need condition here to prevent infinite recursion
using index_type =
typename unpacked_array_type_impl<T,make_index_sequence<rank<T>::value>>::index_type;
}
// Print indices for testing
template<size_t...N>
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]>::index_type x;
// print_sequence(x,cout); // Desired output = [0 0 3 4 5 ]
return 0;
}
`用clang 5.0.1编译,给出错误
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; ^`
是否有可能提取这些尺寸?
注意:我使用自己实现的一些C ++ 14特性,例如C ++ 11中的std::index_sequence
。
编辑:添加代码https://coliru.stacked-crooked.com/a/6776152e348c2c57这构建,但输出[3 4 5]而不是[0 0 3 4 5]
代码中的一些错误。
(1)使用type
或index_type
但不要求type
// .......................................................................vvvv
typename unpacked_array_type_impl<T,make_index_sequence<rank<T>::value>>::type;
当班级定义index_type
时
template<typename T, size_t...I>
struct unpacked_array_type_impl<T,index_sequence<I...>> {
using index_type = index_sequence<extent<T[I]>::value...>;
}; // ..^^^^^^^^^^
同样的问题,unpacked_array_sequence
定义index_type
在main()
你问type
(2)使用std::extent<T, I>::value...
,而不是extent<T[I]>::value...
。
还要观察使用extent<T[I]>::value ...
定义T[0]
(当I
为零时),这在标准C ++中是不可接受的。
(3)之前添加template <std::size_t ... N>
void print_sequence( const index_sequence<N...>& seq, ostream& os ) {
纠正这些错误你应该得到输出
[3 4 5 ]
这不完全是你问的,但是是一种改进。
要得到
[0 0 3 4 5 ]
我建议如下改写unpacked_array_type_impl
template <typename, typename IS = std::index_sequence<>>
struct unpacked_array_type_impl
{ using type = IS; };
template <typename T, std::size_t ... I>
struct unpacked_array_type_impl<T*, std::index_sequence<I...>>
: public unpacked_array_type_impl<T, std::index_sequence<0u, I...>>
{ };
template <typename T, std::size_t N, std::size_t ... I>
struct unpacked_array_type_impl<T[N], std::index_sequence<I...>>
: public unpacked_array_type_impl<T, std::index_sequence<I..., N>>
{ };
并按如下方式使用它
template<typename T>
struct unpacked_array_type
{ using type = typename unpacked_array_type_impl<T>::type; };
以下是一个完整的工作示例
#include <utility>
#include <iostream>
#include <type_traits>
template <typename, typename IS = std::index_sequence<>>
struct unpacked_array_type_impl
{ using type = IS; };
template <typename T, std::size_t ... I>
struct unpacked_array_type_impl<T*, std::index_sequence<I...>>
: public unpacked_array_type_impl<T, std::index_sequence<0u, I...>>
{ };
template <typename T, std::size_t N, std::size_t ... I>
struct unpacked_array_type_impl<T[N], std::index_sequence<I...>>
: public unpacked_array_type_impl<T, std::index_sequence<I..., N>>
{ };
template<typename T>
struct unpacked_array_type
{ using type = typename unpacked_array_type_impl<T>::type; };
// Print indices for testing
template <std::size_t ... N>
void print_sequence (std::index_sequence<N...> const & seq,
std::ostream & os)
{
using expand_type = int[];
os << "[";
(void) expand_type { 0, ((void)(os << N << " ") , 0) ... };
os << "]\n";
}
int main ()
{
typename unpacked_array_type<double**[3][4][5]>::type x;
print_sequence(x, std::cout); // Desired output = [0 0 3 4 5 ]
}