it-swarm.com.ru

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

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

Часть, которую я не получаю, это параметры для этой функции шаблона. Что происходит с массивом, когда я передаю его туда, который дает n в качестве количества элементов в массиве?

60
marsol0x

Ну, во-первых, вы должны понять, что попытка получить значение из массива может дать вам указатель на его первый элемент:

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);

Есть вариант, который я придумал некоторое время назад [Правка: оказывается, у кого-то уже была та же идея здесь ] , которая может определить значение во время компиляции. Вместо непосредственного возврата значения он дает шаблону тип возвращаемого значения в зависимости от 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))];

Поскольку функция никогда не вызывается, ее не нужно определять, поэтому у нее нет тела. Надеюсь, я смогу немного разобраться с этим вопросом.

85
Johannes Schaub - litb

Подумайте об этом так, предположим, у вас было несколько функций:

// 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);  

Теперь, если вы шаблонизируете массив, вы получите:

template <int n>
size_t array_size(const int (&)[n])
{
    return n;
}

Компилятор попытается создать экземпляр версии array_size, который соответствует любому параметру, с которым вы ее вызываете. Так что, если вы вызовете его с массивом из 10-ти дюймов, он создаст экземпляр array_size с n = 10.

Далее просто шаблонизируйте тип, чтобы вы могли вызывать его не только с массивами int:

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

И вы сделали.

Правка: заметка о (&)

Круглые скобки необходимы вокруг &, чтобы различать массив ссылок int (недопустимый) и ссылку на массив int (что вы хотите). Поскольку приоритет [] выше, чем &, если у вас есть объявление:

const int &a[1];

из-за приоритета операторов вы получаете одноэлементный массив константных ссылок на int. Если вы хотите, чтобы & был применен первым, вам нужно принудительно указать его в скобках:

const int (&a)[1];  

Теперь у вас есть константная ссылка на массив элементов с одним элементом. В списке параметров функции вам не нужно указывать имя параметра, если вы его не используете, поэтому вы можете удалить его, но оставьте скобки:

size_t array_size(const int (&)[1])
21
Eclipse

Ничего не происходит с массивом. Это неиспользуемый параметр, который используется для разрешения сигнатуры функции шаблона.

Он также не может использоваться в качестве аргумента шаблона, но это отдельная гнида.

1
MSN

Немного странный способ получить результат как 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;
}
0
TechPriest