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


этот вопрос уже есть ответ здесь:

  • Магические аргументы в шаблонах функций 3 ответы
template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
    return n;
}

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

4 58

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