Иногда приходится иметь дело с обычными массивами и указателями на них в С++. Также иногда встает задача определения количества элементов массиве на стадии компиляции.
Например, это можно слелать так:
#define arraysize(array) (sizeof(array) / sizeof(array[0]))
Но тут есть одна проблема. Если случайно передать в этот макрос не массив, а просто указатель, что ошибки компиляции не будет, но значение будет далеко от задуманного.
Вчера прочитал на Харбе (кстати, отличная статья), что в С++ можно сделать этот макрос более безопасным.
Вот код, который используется в Chrome:
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
Выглядит немного запутанно, но можно разобраться:
- T (&array)[N] - определение массива (T array[N]), который передается по ссылке
- char (&ArraySizeHelper(...)[N] - функция, возвращающая массив по ссылке
- sizeof(ArraySizeHelper(array)) - определение размера возвращаемого функцией значения
- Все это шаблон функции, параметризированный типом массива и его размером, который автоматически определяется компилятором при раскрытии шаблона. Так как функция реально не вызывается, то и тело ее определять не нужно.
Если честно, додуматься до такого непросто. Но макрос весьма хорош. Я взял себе на вооружение.
Кстати, можно поиграться с sizeof() от типа возвращаемого функцией значения:
#include <iostream>
#include <string>
std::string f() {
return std::string();
}
int main() {
std::cout << sizeof( (&f)() ) << std::endl;
std::cout << sizeof( std::string ) << std::endl;
return 0;
}
У меня на VS2010 выводит два раза число "28".
Интересно, что в чистом С такой номер тоже проходит:
#include <stdio.h>
struct t {
char x[1024];
};
struct t f() {
struct t a;
return a;
}
int main() {
printf("%d\n", sizeof(struct t));
printf("%d\n", sizeof( (*f)() ));
return 0;
}
Печатает два раза "1024".
Комментариев нет:
Отправить комментарий