Может кто-нибудь объяснить этот код шаблона, который дает мне размер массива? [дубликат]
этот вопрос уже есть ответ здесь:
- Магические аргументы в шаблонах функций 3 ответы
template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
return n;
}
часть, которую я не получаю, - это параметры для этой функции шаблона. Что происходит с массивом, когда я передаю его туда, что дает n
как количество элементов в массиве?
4 ответа:
ну, сначала вы должны понять, что попытка получить значение из массива может дать вам указатель на его первый элемент:
int a[] = {1, 2, 3}; int *ap = a; // a pointer, size is lost int (&ar)[3] = a; // a reference to the array, size is not lost
ссылки относятся к объектам, использующим их точный тип или тип базового класса. Ключ в том, что шаблон принимает массивы по ссылке. Массивы (не ссылки на них) как параметры не существуют в C++. Если вы зададите параметру тип массива, он будет указателем. Поэтому использование ссылки необходимо, когда мы хотим знать размер переданный массив. Размер и тип элемента выводятся автоматически, как это обычно бывает для шаблонов функций. Следующий шаблон
template<typename T, size_t n> size_t array_size(const T (&)[n]) { return n; }
вызывается с нашим ранее определенным массивом
a
неявно создаст экземпляр следующей функции:size_t array_size(const int (&)[3]) { return 3; }
, который может быть использован такой:
size_t size_of_a = array_size(a);
есть вариант, который я придумал некоторое время назад [Edit: оказывается, у кого-то уже была такая же идея здесь], который может определить значение во время компиляции. Вместо того, чтобы возвращать значение напрямую, он дает шаблону тип возврата в зависимости от
n
:template<typename T, size_t n> char (& array_size(const T (&)[n]) )[n];
вы говорите, если массив имеет
n
элементы, возвращаемый тип является ссылкой на массив размеромn
тип и элементchar
. Теперь вы можете получить определенный во время компиляции размер передаваемого массива:size_t size_of_a = sizeof(array_size(a));
потому что массив
char
Сn
элементы имеет размерn
, что даст вам количество элементов в данном массиве тоже. Во время компиляции, так что вы можете сделатьint havingSameSize[sizeof(array_size(a))];
поскольку функция никогда не вызывается, ее не нужно определять, поэтому у нее нет тела. Надеюсь, я смогу немного прояснить этот вопрос.
подумайте об этом таким образом, предположим, что у вас была куча функций:
// Note that you don't need to name the array, since you don't // actually reference the parameter at all. size_t array_size(const int (&)[1]) { return 1; } size_t array_size(const int (&)[2]) { return 2; } size_t array_size(const int (&)[3]) { return 3; } // etc...
теперь, когда вы вызываете это, какая функция вызывается?
int a[2]; array_size(a);
теперь, если вы templatize arraysize, вы получите:
template <int n> size_t array_size(const int (&)[n]) { return n; }
компилятор попытается создать экземпляр версии array_size, которая соответствует любому параметру, с которым вы его вызываете. Поэтому, если вы вызываете его с массивом 10 ints, он будет создавать экземпляр array_size с n=10.
далее, просто templatize тип, так что вы можете вызвать его с более чем просто int массивы:
template <typename T, int n> size_t array_size(const T (&)[n]) { return n; }
и вы сделали.
Edit: заметка о
(&)
круглые скобки необходимы вокруг
&
чтобы различать массив ссылок int (незаконный) и ссылку на массив ints (что вы хотите). Так как приоритет[]
выше&
, если у вас есть объявление:const int &a[1];
из-за оператора приоритет, вы в конечном итоге с одним-элемент массива константных ссылок на Инт. Если вы хотите
&
применяется во-первых, вам нужно заставить это с круглыми скобками:const int (&a)[1];
теперь у вас есть ссылка const на массив одного элемента ints. В списке параметров функции вам не нужно указывать имя параметра, если вы его не используете, поэтому вы можете удалить имя, но сохранить круглые скобки:
size_t array_size(const int (&)[1])
с массивом ничего не происходит. Это неиспользуемый параметр, который используется для разрешения сигнатуры функции шаблона.
Он также не может быть использован в качестве аргумента шаблона, но это отдельная нить.
немного странный способ получить результат как const времени компиляции для тех из нас, кто не имеет "constexpr":
#include <iostream> namespace { template <size_t V> struct helper { enum { value = V }; }; template<typename T, size_t Size> auto get_size(T(&)[Size]) -> helper < Size > { return helper < Size >() ; } template<typename T> struct get_value { enum { value = T::value }; }; } int main() { std::cout << get_value<decltype(get_size("Foo bar baz"))>::value; }