请考虑以下代码:
#include <iostream>
#include <array>
template <typename, int, int...> struct NArray;
template <typename T, int NUM_DIMENSIONS, int N>
struct NArray<T, NUM_DIMENSIONS, N> {
using type = std::array<T, N>;
};
template <typename T, int NUM_DIMENSIONS, int FIRST, int... REST>
struct NArray<T, NUM_DIMENSIONS, FIRST, REST...> {
using type = std::array<typename NArray<T, NUM_DIMENSIONS, REST...>::type, FIRST>;
};
template <typename T, int NUM_DIMENSIONS, int... N>
typename NArray<T, NUM_DIMENSIONS, N...>::type NDimensionalArray() {
typename NArray<T, NUM_DIMENSIONS, N...>::type nArray;
return nArray;
}
int main() {
const auto nArray = NDimensionalArray<int,4, 2,4,5,3>();
}
我想要的是能够使用更多的int值扩展NDimensionalArray的模板包,以便将某些值初始化为某个指定的固定值。例如,
auto a = NDimensionalArray<bool,4, 2,4,5,3, 1,2,3,2, 0,0,2,1>(true);
将返回一个2x4x5x3的4维std ::数组,其中[1] [2] [3] [2] =真,而[0] [0] [2] [1] =真,并且每隔一个元素错误。但我遇到了多个模板包的问题,似乎无法使其正常运行。任何帮助,将不胜感激。感谢。
答案 0 :(得分:5)
那么这是一个有效的解决方案。如果有人可以改进它,我会非常有兴趣看到它,因为我不知道其他任何方法。
#include <iostream>
#include <array>
#include <cstring>
template <int... > struct seq {};
template <typename, int...> struct NArray;
template <typename T, int N>
struct NArray<T, N> {
using type = std::array<T, N>;
};
template <typename T, int FIRST, int... REST>
struct NArray<T, FIRST, REST...> {
using type = std::array<typename NArray<T, REST...>::type, FIRST>;
};
template <typename T, typename Dim>
struct make_narray;
template <typename T, int... N>
struct make_narray<T, seq<N...>>
{
using type = typename NArray<T, N...>::type;
};
template <typename T>
T& get(T& val, seq<>)
{
return val;
}
template <typename NA, int E0, int... Es>
auto get(NA& arr, seq<E0, Es...>)
-> decltype(get(arr[E0], seq<Es...>{}))
{
return get(arr[E0], seq<Es...>{});
}
template <typename T, typename Dim, typename... Elems>
typename make_narray<T, Dim>::type
NDimensionalArray(T val)
{
typename make_narray<T, Dim>::type narray{};
auto _{get(narray, Elems{}) = val ...}; // Quick initialization step!
return narray;
}
int main() {
auto a = NDimensionalArray<bool, seq<2, 4, 5, 3>, seq<1, 2, 3, 2>, seq<0, 0, 2, 1>>(true);
std::cout << std::boolalpha;
std::cout << a[0][0][0][0] << std::endl; // prints false
std::cout << a[1][2][3][2] << std::endl; // prints true
std::cout << a[0][0][2][1] << std::endl; // prints true
}
答案 1 :(得分:2)
C ++ 14和C ++ 11(第二个演示)中您想要的确切语法NDimensionalArray<bool,4, 2,4,5,3, 1,2,3,2, 0,0,2,1>(true)
:
#include <iostream>
#include <iomanip>
#include <array>
#include <tuple>
#include <utility>
#include <type_traits>
#include <cstddef>
template <typename, int, int...> struct NArray;
template <typename T, int NUM_DIMENSIONS, int N>
struct NArray<T, NUM_DIMENSIONS, N>
{
using type = std::array<T, N>;
};
template <typename T, int NUM_DIMENSIONS, int FIRST, int... REST>
struct NArray<T, NUM_DIMENSIONS, FIRST, REST...>
{
using type = std::array<typename NArray<T, NUM_DIMENSIONS, REST...>::type, FIRST>;
};
template <typename A, typename T>
void assign(A& arr, const T& value)
{
arr = value;
}
template <int I, int... Is, typename A, typename T>
void assign(A& arr, const T& value)
{
assign<Is...>(arr[I], value);
}
template <int SIZE, int PACK, int... Ind, typename T, typename A, std::size_t... Is>
auto set(const T& value, A& arr, std::index_sequence<Is...> seq)
-> std::enable_if_t<(SIZE*PACK == sizeof...(Ind))>
{
}
template <int SIZE, int PACK, int... Ind, typename T, typename A, std::size_t... Is>
auto set(const T& value, A& arr, std::index_sequence<Is...> seq)
-> std::enable_if_t<(SIZE*PACK < sizeof...(Ind))>
{
constexpr auto t = std::make_tuple(Ind...);
assign<std::get<PACK*SIZE+Is>(t)...>(arr, value);
set<SIZE, PACK+1, Ind...>(value, arr, seq);
}
template <typename T, int DIMS, int... N, std::size_t... Is>
auto make_narray(const T& value, std::index_sequence<Is...> seq)
{
constexpr auto t = std::make_tuple(N...);
typename NArray<T, DIMS, std::get<Is>(t)...>::type arr{};
set<DIMS, 1, N...>(value, arr, seq);
return arr;
}
template <typename T, int DIMS, int... N>
auto NDimensionalArray(const T& value)
{
return make_narray<T, DIMS, N...>(value, std::make_index_sequence<DIMS>{});
}
int main()
{
auto a = NDimensionalArray<bool,4, 2,4,5,3, 1,2,3,2, 0,0,2,1>(true);
std::cout << std::boolalpha;
std::cout << a[1][2][3][2] << std::endl; // ~~~~^
std::cout << a[0][0][2][1] << std::endl; // ~~~~~~~~~~~~^
std::cout << a[0][0][0][0] << std::endl; // (not set)
}
输出:
true
true
false
答案 2 :(得分:1)
解决方案包含参数包ARGS&&... args
中的初始化位置:
#include <array>
#include <iostream>
#include <deque>
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 <typename E, typename Container, typename T>
void assign (E& element, Container&&, const T& v) { element = v; }
template <typename Subarray, std::size_t N, typename Container, typename T>
void assign (std::array<Subarray, N>& narray, Container&& pos, const T& v) {
const std::size_t index = pos.front();
pos.pop_front();
assign (narray[index], pos, v);
}
template <typename T, int... Dimensions, typename... Args>
typename NArray<T, Dimensions...>::type NDimensionalArray (const T& value, Args&&... args) {
typename NArray<T, Dimensions...>::type narray{};
const auto initializer = {std::forward<Args>(args)...};
const int groupSize = sizeof...(Dimensions), numGroups = initializer.size() / groupSize;
for (std::size_t i = 0; i < numGroups; i++)
assign (narray, std::deque<std::size_t>(initializer.begin() + i*groupSize, initializer.begin() + (i+1)*groupSize), value);
return narray;
}
int main() {
const auto multiArray = NDimensionalArray<double, 5,6,7,8,9> (3.14, 1,2,3,2,4, 3,3,2,1,2, 0,1,3,1,2);
std::cout << multiArray[1][2][3][2][4] << '\n'; // 3.14
std::cout << multiArray[3][3][2][1][2] << '\n'; // 3.14
std::cout << multiArray[0][1][3][1][2] << '\n'; // 3.14
}
答案 3 :(得分:0)
这是Piotr的解决方案,通过删除他的enable_if特化并再次使用索引技巧来整理一下。此外,我已经为任意数量的设置值推广了以下示例语法:
makeNDimensionalArray<char, I<3,6,5,4>, I<2,4,3,2, 0,1,2,3, 1,2,4,3>, I<0,0,0,0, 2,3,1,2>, I<1,1,2,1>>('a','b','c')
其中I<3,6,5,4>
设置多数组的维度。然后I<2,4,3,2, 0,1,2,3, 1,2,4,3>
将数组的三个索引位置设置为'a',I<0,0,0,0, 2,3,1,2>
将数组的两个索引位置设置为'b',依此类推。
#include <iostream>
#include <array>
#include <tuple>
#include <utility>
template <typename, std::size_t, std::size_t...> struct NArray;
template <typename T, std::size_t NumDimensions, std::size_t N>
struct NArray<T, NumDimensions, N> {
using type = std::array<T, N>;
};
template <typename T, std::size_t NumDimensions, std::size_t First, std::size_t... Rest>
struct NArray<T, NumDimensions, First, Rest...> {
using type = std::array<typename NArray<T, NumDimensions, Rest...>::type, First>;
};
template <typename T, std::size_t... Dimensions>
using NDimensionalArray = typename NArray<T, sizeof...(Dimensions), Dimensions...>::type;
template <typename T, typename Dimensions> struct NArrayFromPack;
template <typename T, template <std::size_t...> class P, std::size_t... Dimensions>
struct NArrayFromPack<T, P<Dimensions...>> : NArray<T, sizeof...(Dimensions), Dimensions...> {
static constexpr std::size_t num_dimensions = sizeof...(Dimensions);
};
template <typename A, typename T>
void setArrayValue (A& a, const T& t) { a = t; }
template <std::size_t First, std::size_t... Rest, typename Array, typename T>
void setArrayValue (Array& array, const T& t) {
setArrayValue<Rest...>(array[First], t);
}
template <typename Indices, typename Sequence> struct InitializeArray;
template <template <std::size_t...> class P, std::size_t... Is, std::size_t... Js>
struct InitializeArray<P<Is...>, std::index_sequence<Js...>> {
template <typename Array, typename T>
static void execute (Array& array, const T& t) {
constexpr std::size_t GroupSize = sizeof...(Js), NumGroups = sizeof...(Is) / GroupSize;
set<GroupSize>(array, t, std::make_index_sequence<NumGroups>{});
}
private:
template <std::size_t GroupSize, typename Array, typename T, std::size_t... Ks>
static void set (Array& array, const T& t, std::index_sequence<Ks...>) {
const int dummy[] = {(do_set<Ks, GroupSize>(array, t), 0)...};
static_cast<void>(dummy);
}
template <std::size_t N, std::size_t GroupSize, typename Array, typename T>
static void do_set (Array& array, const T& t) {
constexpr std::size_t a[] = {Is...};
setArrayValue<a[N*GroupSize + Js]...>(array, t);
}
};
template <typename T, typename Dimensions, typename... Indices, typename... Args>
auto makeNDimensionalArray (const Args&... args) {
using A = NArrayFromPack<T, Dimensions>;
typename A::type array;
const int a[] = {(InitializeArray<Indices, std::make_index_sequence<A::num_dimensions>>::execute(array, args), 0)...};
static_cast<void>(a);
return array;
}
template <std::size_t...> struct I;
int main() {
const NDimensionalArray<char, 3,6,5,4> a = makeNDimensionalArray<char, I<3,6,5,4>, I<2,4,3,2, 0,1,2,3, 1,2,4,3>, I<0,0,0,0, 2,3,1,2>, I<1,1,2,1>>('a','b','c');
std::cout << a[2][4][3][2] << std::endl; // a
std::cout << a[0][1][2][3] << std::endl; // a
std::cout << a[1][2][4][3] << std::endl; // a
std::cout << a[0][0][0][0] << std::endl; // b
std::cout << a[2][3][1][2] << std::endl; // b
std::cout << a[1][1][2][1] << std::endl; // c
}