может кто-нибудь объяснить этот шаблон кода, который дает мне размер массива?

<pre><code>template<typename t, size\_t n> size\_t array\_size(const t (&)[n]) { return n; } </code></pre><p>часть, которую я не получаю, это параметры для этой функции шаблона. что происходит с массивом, когда я передаю его туда, который дает <code>n</code> в качестве количества элементов в массиве?</p>

<p>ну, во-первых, вы должны понять, что попытка получить значение из массива может дать вам указатель на его первый элемент:</p><pre><code>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 </code></pre><p>ссылки ссылаются на объекты, используя их точный тип или тип базового класса. ключ в том, что шаблон принимает массивы по ссылке. массивы (не ссылки на них) как параметры не существуют в c++. если вы дадите параметру тип массива, он будет указателем. поэтому использование ссылки необходимо, когда мы хотим узнать размер передаваемого массива. размер и тип элемента определяются автоматически, как это обычно бывает для шаблонов функций. следующий шаблон</p><pre><code>template<typename t, size\_t n> size\_t array\_size(const t (&)[n]) { return n; } </code></pre><p>вызванный нашим ранее определенным массивом <code>a</code> неявно создаст следующую функцию</p><pre><code>size\_t array\_size(const int (&)[3]) { return 3; } </code></pre><p>который можно использовать так:</p><pre><code>size\_t size\_of\_a = array\_size(a); </code></pre><hr><p>есть вариант, который я придумал некоторое время назад <em> [правка: оказывается, у кого-то уже была та же идея <a href="http://blogs.msdn.com/the1/archive/2004/05/07/128242.aspx">здесь</a> ] </em>, которая может определить значение во время компиляции. вместо непосредственного возврата значения он дает шаблону тип возвращаемого значения в зависимости от <code>n</code></p><pre><code>template<typename t, size\_t n> char (& array\_size(const t (&)[n]) )[n]; </code></pre><p>вы говорите, что если массив содержит элементы <code>n</code>, возвращаемый тип является ссылкой на массив, имеющий размер <code>n</code> и тип элемента <code>char</code>. теперь вы можете получить размер переданного массива во время компиляции:</p><pre><code>size\_t size\_of\_a = sizeof(array\_size(a)); </code></pre><p>поскольку массив <code>char</code>, имеющий элементы <code>n</code>, имеет размер <code>n</code>, это также даст вам количество элементов в данном массиве. во время компиляции, так что вы можете сделать</p><pre><code>int havingsamesize[sizeof(array\_size(a))]; </code></pre><p>поскольку функция никогда не вызывается, ее не нужно определять, поэтому у нее нет тела. надеюсь, я смогу немного разобраться с этим вопросом.</p>

<p>подумайте об этом так, предположим, у вас было несколько функций:</p><pre><code>// 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... </code></pre><p>теперь, когда вы вызываете это, какая функция вызывается?</p><pre><code>int a[2]; array\_size(a); </code></pre><p>теперь, если вы шаблонизируете массив, вы получите:</p><pre><code>template <int n> size\_t array\_size(const int (&)[n]) { return n; } </code></pre><p>компилятор попытается создать экземпляр версии array\_size, который соответствует любому параметру, с которым вы ее вызываете. так что, если вы вызовете его с массивом из 10-ти дюймов, он создаст экземпляр array\_size с n = 10.</p><p>далее просто шаблонизируйте тип, чтобы вы могли вызывать его не только с массивами int:</p><pre><code>template <typename t, int n> size\_t array\_size(const t (&)[n]) { return n; } </code></pre><p>и вы сделали.</p><p><strong>правка</strong>: заметка о <code>(&)</code></p><p>круглые скобки необходимы вокруг <code>&</code>, чтобы различать массив ссылок int (недопустимый) и ссылку на массив int (что вы хотите). поскольку приоритет <code>[]</code> выше, чем <code>&</code>, если у вас есть объявление:</p><pre><code>const int &a[1]; </code></pre><p>из-за приоритета операторов вы получаете одноэлементный массив константных ссылок на int. если вы хотите, чтобы <code>&</code> был применен первым, вам нужно принудительно указать его в скобках:</p><pre><code>const int (&a)[1]; </code></pre><p>теперь у вас есть константная ссылка на массив элементов с одним элементом. в списке параметров функции вам не нужно указывать имя параметра, если вы его не используете, поэтому вы можете удалить его, но оставьте скобки:</p><pre><code>size\_t array\_size(const int (&)[1]) </code></pre>

<p>ничего не происходит с массивом. это неиспользуемый параметр, который используется для разрешения сигнатуры функции шаблона.</p><p>он также не может использоваться в качестве аргумента шаблона, но это отдельная гнида.</p>

<p>немного странный способ получить результат как const во время компиляции для тех из нас, у кого нет "constexpr":</p><pre><code>#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; } </code></pre>