Alguém pode explicar esse código de modelo que me dá o tamanho de uma matriz? [duplicado]

StackOverflow https://stackoverflow.com/questions/437150

  •  22-07-2019
  •  | 
  •  

Pergunta

Esta questão já tem uma resposta aqui:

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

A parte que eu não entendo é os parâmetros para esta função de modelo. O que acontece com a matriz quando eu passá-lo por lá que dá n como o número de elementos na matriz?

Foi útil?

Solução

Bem, primeiro você tem que entender que a tentativa de obter um valor de um array pode dar-lhe um ponteiro para seu primeiro elemento:

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

As referências se referem a objetos usando seu tipo exato ou seu tipo de classe base. A chave é que o molde toma matrizes por referência. Arrays (não referências a eles) como parâmetros não existem no C ++. Se você dá um parâmetro de um tipo de matriz, será um ponteiro em vez. Então, usando uma referência é necessária quando queremos saber o tamanho da matriz passada. O tamanho eo tipo de elemento são automaticamente deduzido, como é geralmente o caso de modelos de função. O modelo a seguir

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

Chamado com a nossa a gama previamente definida instanciará implicitamente a seguinte função:

size_t array_size(const int (&)[3]) {
    return 3;
}

Que pode ser usado como este:

size_t size_of_a = array_size(a);

Há uma variação que fiz até algum tempo atrás [Edit: Acontece que alguém já teve essa mesma idéia aqui ] que pode determinar um valor em tempo de compilação. Em vez de retornar o valor diretamente, dá ao modelo um tipo de retorno dependendo n:

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

Você diz que se a matriz tem elementos n, o tipo de retorno é uma referência a uma matriz tendo n tamanho e tipo de elemento char. Agora, você pode obter um tempo de compilação tamanho determinado da matriz passada:

size_t size_of_a = sizeof(array_size(a));

Porque uma série de char ter elementos n tem n sizeof, que lhe dará o número de elementos na matriz dada também. Em tempo de compilação, de modo que você pode fazer

int havingSameSize[sizeof(array_size(a))];

Como a função não é realmente chamado, ele não precisa ser definido, para que ele não tem um corpo. Espero que eu poderia esclarecer o assunto um pouco.

Outras dicas

Pense nisso desta maneira, suponha que você tinha um monte de funções:

// 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...

Agora, quando você chama este, cuja função é chamado?

int a[2];
array_size(a);  

Agora, se você templatize o ArraySize, você obtém:

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

O compilador tentará instanciar uma versão do ARRAY_SIZE que corresponde a qualquer parâmetro que você chamá-lo com. Então, se você chamá-lo com um array de 10 inteiros, ele irá instanciar ARRAY_SIZE com n = 10.

Em seguida, apenas templatize o tipo, de modo que você pode chamá-lo com mais de matrizes apenas int:

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

E você está feito.

Editar : Uma nota sobre a (&)

Os parênteses são necessários em todo o & para diferenciar entre array de referências int (ilegais) e referência a matriz de ints (o que você quiser). Desde a precedência de [] é maior do que &, se você tiver a declaração:

const int &a[1];

por causa da precedência do operador, você acaba com uma matriz de um elemento de referências const para int. Se quiser que o & aplicado pela primeira vez, você precisa de força que, com parênteses:

const int (&a)[1];  

Agora, o que você tem uma referência const para uma matriz, um elemento de inteiros. Na lista de parâmetros função, você não precisa especificar o nome de um parâmetro se você não usá-lo, então você pode deixar cair o nome, mas manter os parênteses:

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

Nada acontece para a matriz. É um parâmetro não utilizado que é usado para resolver a assinatura da função de modelo.

Ele também não pode ser usado como um argumento de modelo, mas isso é um nit separado.

Um pouco estranho para obter o resultado como const em tempo de compilação para aqueles de nós que não têm "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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top