My question refers to a question I’ve asked previously for a single-dimensional array:
Can someone please help me extend the use of the indices trick to multiple dimensional arrays, such as in this example:
template<unsigned...> struct indices
{
};
template<unsigned M, unsigned... Is> struct indices_gen
: indices_gen<M - 1, M - 1, Is...>
{
};
template<unsigned... Is> struct indices_gen<0, Is...> : indices<Is...>
{
};
template <typename T>
struct example
{
template<typename ...U, typename
= typename std::enable_if<all_of<std::is_same<U, T>...>::value>::type>
example(U... args)
{
static_assert(3 * 2 == sizeof...(U),
"wrong number of arguments in assignment");
assign(indices_gen<M * N>(), args...);
}
template<size_type... Is, class... U>
void assign(indices<Is...>, U... args)
{
[](...){}(((&array[0][0])[Is] = args)...);
}
T array[3][2];
};
int main()
{
example<int> ex(1, 2, 3, 4, 5, 6);
return 0;
}
Currently I depend on the requirement, that arrays are contiguous, but I’d like to assign array using pairs of indices, not just a single index (this way I’d be able to support types other than arrays, in particular, types that override operator[]). If I use 2 argument packs for assignment, I’ll assign only at indices (0, 0), (1, 1), …, also there is a small problem with argument packs not having the same lengths when dimensions of the array differ (as in the example).
This can be made a lot easier by changing the code to access the array, not the indices generation. What you basically want is a 1D to 2D access mapping.
Normally, people need it the other way around (2D to 1D), when they implement a 2D array in terms of a 1D array†:
The formula to get the 1D index
ifrom the 2D index(x,y)is theni == x * N + y. We can explain this if we imagine our 1Delemsfrom above as a 2D array (usingM == 2andN == 3):Thus, we get
i == x * N + y. We now need to solve this formula not foribut forxandy. Forx, it’s rather easy (using math notation):So
x == (i - y) / N. Now, sadly, I don’t know how to solve this foryusing pure math, but we don’t need that. Taking a look at the element indices, we can see that they wrap aroundN, and that can easily be done using the modulo operator. Thus,y == i % N.Now we can implement a method that takes a linear index
iand returns the element at the solved(x, y)from that:and generalizing that:
Using
constexprto ensure that all the computation is done at compile-time.Now you can simply write
assignas follows:Q.E.D. (Live example.)
† Now, you can make this easier on yourself by actually implementing the 2D array as a 1D array. 🙂 This way, you can straight-forwardly use
(array[Is] = args)...and for the other cases use a simple access function that does the mapping:Live example.