#c #arrays
#c #массивы
Вопрос:
Это код, который я нашел в Интернете.
template<class T, unsigned ... RestD> struct array;
template<class T, unsigned PrimaryD >
struct array<T, PrimaryD>
{
typedef T type[PrimaryD];
type data;
Tamp; operator[](unsigned i) { return data[i]; }
};
template<class T, unsigned PrimaryD, unsigned ... RestD >
struct array<T, PrimaryD, RestD...>
{
typedef typename array<T, RestD...>::type OneDimensionDownArrayT;
typedef OneDimensionDownArrayT type[PrimaryD];
type data;
OneDimensionDownArrayTamp; operator[](unsigned i) { return data[i]; }
};
int main()
{
array<int, 2, 3>::type a4 = { { 1, 2, 3}, { 1, 2, 3} };
array<int, 2, 3> a5{ { { 1, 2, 3}, { 4, 5, 6} } };
std::cout << a5[1][2] << std::endl;
array<int, 3> a6{ {1, 2, 3} };
std::cout << a6[1] << std::endl;
array<int, 1, 2, 3> a7{ { { { 1, 2, 3}, { 4, 5, 6 } } }};
std::cout << a7[0][1][2] << std::endl;
}
Не могли бы вы объяснить, что именно делает этот код? Я понимаю, что рекурсия используется в той или иной форме здесь для создания многомерного массива, но я немного смущен тем, как работает этот процесс.
Меня также смущает эта строка:
array<int, 2, 3>::type a4 = { { 1, 2, 3}, { 1, 2, 3} };
Что такое ::type ?
Ответ №1:
Это то, что называется специализацией шаблонов.
Первое, что вы должны знать, это то, что все, что определено с template
помощью, оценивается во время компиляции.
Глядя на ваш код, мы хотим рассмотреть два основных случая:
- Когда массив имеет одномерность
- Когда массив имеет более одного измерения
Ниже описывается одномерный случай:
template<class T, unsigned PrimaryD >
struct array<T, PrimaryD>
{
typedef T type[PrimaryD];
type data;
Tamp; operator[](unsigned i) { return data[i]; }
};
Как вы можете видеть, приведенная выше структура специализирована для приема только двух параметров шаблона, первый T
— это тип данных массива, а второй — PrimaryD
это просто означает, какой длины должен быть массив.
Теперь для 2-й специализации:
template<class T, unsigned PrimaryD, unsigned ... RestD >
struct array<T, PrimaryD, RestD...>
{
// if the template contains array<int, 1, 2, 3, 4>
// then RestD... will unpack the values 2, 3, 4
typedef typename array<T, RestD...>::type
OneDimensionDownArrayT;
typedef OneDimensionDownArrayT type[PrimaryD];
type data;
// This will return an array type
// you can keep on making a call to operator[] until the type of the OneDimensionDownArrayT refers to the previous specialization
OneDimensionDownArrayTamp; operator[](unsigned i) { return
data[i];
}
};
Теперь для вашего примера:
array<int, 2, 3>::type a4 = { { 1, 2, 3}, { 1, 2, 3} }
Что будет делать компилятор, так это сопоставлять параметры шаблона, а именно, int
, 2
, и 3
которые оцениваются по 2-й специализации.
Давайте проследим за этим:
array<int, 2, 3>
какая структура содержит следующие конкретные типы: OneDimensionalT, который равен array<int, 3> и operator[] функция, которая возвращает array<int, 3> .
OneDimensionalT равно array<int, 3> потому что, если вы распакуете RestD...
значения, которые вы получите 3
, 2
они уже используются первым параметром шаблона, PrimaryD
.
Добавление 3-го измерения следует той же логике, продолжайте рекурсивно определять типы структурных массивов меньшего размера, используя только значения измерений n-1 пакета параметров RestD...
О, и кстати, строка сверху предназначена только для объявления базового типа, чтобы мы могли его специализировать.
Комментарии:
1. Спасибо за ваш ответ! Чрезвычайно краткое объяснение проблемы, с которой я долго боролся, большое вам спасибо!