Иногда приходится иметь дело с обычными массивами и указателями на них в С++. Также иногда встает задача определения количества элементов массиве на стадии компиляции.
Например, это можно слелать так:
#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”.