【发布时间】:2016-07-23 04:20:45
【问题描述】:
函数createMultiArray<M,N>()创建一个
`std::array<std::array<std::tuple<std::size_t, std::size_t>, M>, N>`,
他们的元素是:
(0, 0) (0, 1) (0, 2) (0, 3)
(1, 0) (1, 1) (1, 2) (1, 3)
(2, 0) (2, 1) (2, 2) (2, 3)
这是我的简单实现:
#include <iostream>
#include <tuple>
#include <utility>
template <std::size_t M, std::size_t N>
struct InitializeMultiArray {
using Array = std::array<std::array<std::tuple<std::size_t, std::size_t>, M>, N>;
template <std::size_t... Is>
static Array execute (std::index_sequence<Is...>) {
Array array;
const int a[] = {(initialize<Is>(array, std::make_index_sequence<M>{}), 0)...};
static_cast<void>(a);
return array;
}
private:
template <std::size_t I, std::size_t... Is>
static void initialize (Array& array, std::index_sequence<Is...>) {
const int a[] = {(array[I][Is] = std::make_tuple(I, Is), 0)...};
static_cast<void>(a);
}
};
template <std::size_t M, std::size_t N>
std::array<std::array<std::tuple<std::size_t, std::size_t>, M>, N> createMultiArray() {
return InitializeMultiArray<M,N>::execute(std::make_index_sequence<N>{});
}
int main() {
constexpr std::size_t M = 4, N = 3;
const std::array<std::array<std::tuple<std::size_t, std::size_t>, M>, N> array = createMultiArray<M,N>();
for (std::size_t i = 0; i < N; i++) {
for (std::size_t j = 0; j < M; j++)
std::cout << "(" << std::get<0>(array[i][j]) << ", " << std::get<1>(array[i][j]) << ") ";
std::cout << '\n';
}
}
现在我需要将createMultiArray<M,N>() 扩展到createMultiArray<Dimensions...>() 到任意数量的维度,例如array[i][j][k]...[last] = std::make_tuple(i,j,k,...,last)。我坚持如何进行这种概括。有人可以帮忙吗?
这里是存储在多维数组中的精确元组类型:
template <std::size_t N>
using Type = std::size_t;
template <typename> struct TupleOfIntsHelper;
template <std::size_t... Is>
struct TupleOfIntsHelper<std::index_sequence<Is...>> {
using type = std::tuple<Type<Is>...>;
};
template <std::size_t N>
using TupleOfInts = typename TupleOfIntsHelper<std::make_index_sequence<N>>::type;
// ...
static_assert (std::is_same<TupleOfInts<3>, std::tuple<std::size_t, std::size_t, std::size_t>>::value, "");
那么createMultiArray<Dimensions...>()的返回类型就是
typename NArray<TupleOfInts<sizeof...(Dimensions)>, Dimensions...>::type
在哪里
template <typename, std::size_t...> struct NArray;
template <typename T, std::size_t N>
struct NArray<T,N> {
using type = std::array<T,N>;
};
template <typename T, std::size_t First, std::size_t... Rest>
struct NArray<T, First, Rest...> {
using type = std::array<typename NArray<T, Rest...>::type, First>;
};
所以唯一困难的任务就是按照上面的讨论来初始化它:
template <std::size_t... Dimensions>
typename NArray<TupleOfInts<sizeof...(Dimensions)>, Dimensions...>::type createMultiArray() {
typename NArray<TupleOfInts<sizeof...(Dimensions)>, Dimensions...>::type array;
// ???
return array;
}
更新:这是我的一个想法:
template <typename... IndexSequences>
struct AllCombinations {
using type = std::tuple<std::index_sequence<0,0,0>, std::index_sequence<0,0,1>>; // etc...
// Generate these based on IndexSequences...
};
template <typename Combinations, typename Array>
void initialize (Array& array) {
// Use each type in Combinations to initialize 'array' via a function like
// void initialize_impl(Array& array, std::index_sequence<Is...>) {
// get_array_element(array, {Is...}) = std::make_tuple(Is...);
// }
}
template <std::size_t... Dimensions>
typename NArray<TupleOfInts<sizeof...(Dimensions)>, Dimensions...>::type createMultiArray() {
typename NArray<TupleOfInts<sizeof...(Dimensions)>, Dimensions...>::type array;
using Combinations = typename AllCombinations<std::make_index_sequence<Dimensions>...>::type;
initialize<Combinations>(array);
return array;
}
这是我上面提到的initialize_impl 函数:
template <std::size_t I>
struct MultiArrayGet {
template <typename Array, std::size_t N>
static auto& get (Array& a, const std::array<std::size_t, N>& index) {
return MultiArrayGet<I - 1>::get(a[index[N - I]], index); // Here I is just a counter so that we know when to stop.
}
};
template <>
struct MultiArrayGet<0> {
template <typename T, std::size_t N>
static auto& get (T& t, const std::array<std::size_t, N>&) { return t; }
};
template <std::size_t N, typename Array>
auto& get_array_element (Array& a, const std::array<std::size_t, N>& index) {
return MultiArrayGet<N>::get(a, index);
}
template <typename Array, std::size_t... Is>
void initialize_impl (Array& array, std::index_sequence<Is...>) {
get_array_element<sizeof...(Is)>(array, {Is...}) = std::make_tuple(Is...);
}
【问题讨论】:
标签: c++ templates multidimensional-array c++14 variadic-templates