Ответ 1
Сначала рассмотрим параметр T(&)[size]
. Сначала читать декларации изнутри, справа налево, группу скобок: это неназванный параметр, который является ссылкой на массив размера size
типа T
.
То есть, он принимает ссылку на любой массив, где тип и размер массива являются параметрами шаблона.
Если мы назовем это следующим:
int a[10];
GetArrLength(a);
Компилятор попытается вывести параметры шаблона. Для того чтобы тип параметра соответствовал тому, что вы передаете, T
должен быть int
и size
должен быть 10 (что делает параметр ссылкой на массив из 10 int
s).
Затем вы возвращаете этот размер, указывая количество элементов в массиве.
В этом коде есть две проблемы. Во-первых, размеры не могут быть отрицательными, поэтому нет смысла использовать подписанный тип в качестве параметра шаблона и типа возврата. Вместо этого следует использовать неподписанный тип; лучше всего было бы std::size_t
:
template<typename T, std::size_t Size>
std::size_t GetArrLength(T(&)[Size]) { return size; }
Во-вторых, результат этой функции не является константным выражением, даже если размер массива. Хотя это прекрасно в большинстве ситуаций, было бы лучше, если бы мы могли получить от него постоянное выражение. То, что вы в конечном итоге с этим решением:
template <std::size_t N>
struct type_of_size
{
typedef char type[N];
};
template <typename T, std::size_t Size>
typename type_of_size<Size>::type& sizeof_array_helper(T(&)[Size]);
#define sizeof_array(pArray) sizeof(sizeof_array_helper(pArray))
Это используется как таковое:
int a[10];
const std::size_t n = sizeof_array(a); // constant-expression!
Он работает по трем вещам: первая - это та же идея, что и выше, что параметры шаблона будут заполнены, что даст вам размер массива.
Вторая часть использует эту информацию для создания типа с определенным размером, поэтому помощник type_of_size
. Эта часть не является строго необходимой, но я думаю, что это упрощает чтение кода. A char[N]
имеет размер, равный N
, всегда, поэтому мы можем злоупотреблять этим, чтобы "хранить" размер массива... в размере самого типа!
Третья часть получает этот размер с помощью sizeof
. На самом деле это ничего не оценивает, поэтому нам не нужно определение функции. Он просто говорит: "Если бы вы сделали это... размер был бы...". Размер - наш "сохраненный" размер в массиве char
.