Как работает этот шаблон размера массива? - PullRequest
16 голосов
/ 16 июня 2011

Я сталкивался с этим фрагментом

template <typename T, size_t N>  
char (&ArraySizeHelper(T (&array)[N]))[N];  
#define arraysize(array) (sizeof(ArraySizeHelper(array))) 

в этой статье http://software.intel.com/en-us/articles/pvs-studio-vs-chromium/

Я видел другие шаблоны, которые делают то же самое, например, этот

Используйте шаблоны, чтобы получить размер массива и конечный адрес

, и я понимаю это, но у меня были трудности с этим.

Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

11 голосов
/ 16 июня 2011

Шаблон функции называется ArraySizeHelper, для функции, которая принимает один аргумент, ссылку на T [N] и возвращает ссылку на char [N].

Макрос передает ваш объект (скажем, X obj[M]) в качестве аргумента. Компилятор выводит, что T == X и N == M. Поэтому он объявляет функцию с типом возвращаемого значения char (&)[M]. Макрос затем оборачивает это возвращаемое значение с sizeof, поэтому он действительно делает sizeof(char [M]), то есть M.

Если вы укажете тип, не являющийся массивом (например, T *), вывод параметров шаблона завершится неудачей.

Как указывает @Alf ниже, преимущество этой гибридной системы шаблонов-макросов по сравнению с альтернативным подходом только на основе шаблонов заключается в том, что это дает вам постоянную времени компиляции.

7 голосов
/ 16 июня 2011

Это не самый хороший способ сделать это, но так как вы спрашиваете: тип возвращаемого значения функции шаблона ArraySizeHelper равен char[N], где аргумент функции - это массив (ссылка на)размером N типа T.Вывод аргумента шаблона создает экземпляр этого шаблона с совпадающим числом N, и поэтому sizeof(char[N]) - это просто N, и это то, что вы получаете.

Более приятная версия может быть написана следующим образом.(Вам нужно C ++ 0x для constexpr; если вы его опустите, это не будет константным выражением.)

template <typename T, size_t N> constexpr size_t array_size(const T (&)[N]) { return N; }

Использование:

int x[20];
array_size(x); // == 20

Обновление: Если вы находитесь в C ++ 0x, вот еще одно решение, которое дает constexpr, благодаря decltype:

#include <type_traits>

template <typename T> struct array_traits;
template <typename T, unsigned int N> struct array_traits<T[N]>
{
   static const unsigned int size = N;
   typedef std::decay<T>::type type;
};

// Usage:
int x[20];
array_traits<decltype(x)>::size; // == 20
4 голосов
/ 17 июня 2011

Этот блог на MSDN точно описывает, как это работает.Очень интересная история.Посмотрите на это.

...