Alguém pode explicar esse código de modelo que me dá o tamanho de uma matriz? [duplicado]
Pergunta
Esta questão já tem uma resposta aqui:
- argumentos mágicas em modelos de função 3 respostas
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?
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;
}