Ответ 1
На самом деле это действительно сложно объяснить, но я попробую...
Во-первых, dimof
сообщает вам измерение или количество элементов в массиве. (Я считаю, что "измерение" является предпочтительной терминологией в средах программирования Windows).
Это необходимо, потому что C++
и C
не дают вам собственного способа определения размера массива.
Часто люди предполагают, что sizeof(myArray)
будет работать, но это фактически даст вам размер в памяти, а не количество элементов. Каждый элемент, вероятно, занимает более 1 байта памяти!
Затем они могут попробовать sizeof(myArray) / sizeof(myArray[0])
. Это дало бы размер в памяти массива, деленный на размер первого элемента. Это нормально и широко используется в коде C
. Основная проблема заключается в том, что он будет работать, если вы передадите указатель вместо массива. Размер указателя в памяти обычно составляет 4 или 8 байт, даже если он указывает на массив из 1000 элементов.
Итак, следующая вещь, которую нужно попробовать в C++
, - это использовать шаблоны для принудительной обработки чего-то, что работает только для массивов и приведет к ошибке компилятора в указателе. Это выглядит так:
template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"
Шаблон будет работать только с массивом. Он выведет тип (не очень необходимый, но должен присутствовать, чтобы шаблон работал) и размер массива, а затем вернет размер. Способ написания шаблона не может работать с указателем.
Обычно вы можете остановиться здесь, и это в C++ Standard Libary как std::size
.
Внимание: ниже здесь он попадает на территорию юристов с волосатыми языками.
Это довольно круто, но все равно не удается в неясном случае:
struct Placeholder {
static float x[8];
};
template <typename T, int N>
int ArraySize (T (&)[N])
{
return N;
}
int main()
{
return ArraySize(Placeholder::x);
}
Обратите внимание, что массив x
объявлен, но не определен. Чтобы вызвать функцию (т.е. ArraySize
) с ней, x
должен быть определен.
In function 'main':
SO.cpp:(.text+0x5): undefined reference to 'Placeholder::x'
collect2: error: ld returned 1 exit status
Вы не можете связать это.
Код, который у вас есть в вопросе, помогает обойти это. Вместо фактического вызова функции, мы объявляем функцию, которая возвращает объект точно правильного размера. Затем мы используем трюк sizeof
.
Похоже, мы вызываем функцию, но sizeof
является чисто конструкцией времени компиляции, поэтому функция никогда не вызывается.
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
^^^^ ^ ^^^
// a function that returns a reference to array of N chars - the size of this array in memory will be exactly N bytes
Обратите внимание, что вы на самом деле не можете вернуть массив из функции, но вы можете вернуть ссылку на массив.
Тогда DimofSizeHelper(myArray)
- это выражение, чей тип является массивом из N
char
s. Выражение на самом деле не обязательно должно выполняться, но оно имеет смысл во время компиляции.
Поэтому sizeof(DimofSizeHelper(myArray))
сообщит вам размер во время компиляции того, что вы получите, если вы действительно вызовете функцию. Хотя мы на самом деле не называем это.
Не волнуйтесь, если последний блок не имеет никакого смысла. Это странный трюк, чтобы обойти причудливый крайний случай. Вот почему вы сами не пишете такого рода код, и позволяете разработчикам библиотек беспокоиться о такой ерунде.