Kann jemand dieses Template-Code erklären, die mir die Größe eines Arrays gibt? [Duplikat]

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

  •  22-07-2019
  •  | 
  •  

Frage

    

Diese Frage bereits eine Antwort hier:

    
            
  •              Magie Argumente in Funktionsschablonen                                      3 Antworten                          
  •     
    
template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
    return n;
}

Der Teil, den ich nicht bekommen, ist die Parameter für diese Template-Funktion. Was passiert mit dem Array, wenn ich es durch es passieren, dass n als die Anzahl der Elemente im Array gibt?

War es hilfreich?

Lösung

Nun, zuerst müssen Sie verstehen, dass ein Wert aus einem Array zu bekommen versuchen, können Sie einen Zeiger auf das erste Element geben:

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

Verweise beziehen sich auf Objekte anhand ihrer genauen Typ oder ihrer Basis-Klasse-Typ. Der Schlüssel ist, dass die Template-Arrays durch Bezugnahme erfolgt. Arrays (nicht Verweise auf sie) als Parameter existieren nicht in C ++. Wenn Sie einen Parameter ein Array-Typ geben, es wird stattdessen ein Zeiger sein. So eine Referenz verwendet, ist notwendig, wenn wir die Größe des übergebenen Array wissen wollen. Die Größe und der Elementtyp automatisch abgeleitet, wie dies allgemein der Fall ist für Funktionsschablonen sind. Die folgende Vorlage

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

Called mit unserer zuvor definierten Array a wird die folgende Funktion implizit instanziiert:

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

, die wie folgt verwendet werden:

size_t size_of_a = array_size(a);

Es gibt eine Variation ich vor einiger Zeit aus [Edit: stellt sich heraus, jemand hatte bereits das gleiche Idee hier ] , die einen Wert zum Zeitpunkt der Kompilierung bestimmen kann. Statt direkt den Wert der Rücksendung, es gibt der Vorlage einen Rückgabetyp je nach n:

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

Sie sagen, wenn die Array-Elemente n hat, der Rückgabetyp eine Referenz auf ein Array ist Größe n mit und Elementtyp char. Jetzt können Sie eine Compiler-bestimmte Größe des übergebenen Array erhalten:

size_t size_of_a = sizeof(array_size(a));

Da eine Reihe von char n Elementen sizeof n hat, das wird Ihnen die Anzahl der Elemente in dem zu array. Bei der Kompilierung, so dass Sie tun können,

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

Da die Funktion eigentlich nie genannt wird, braucht es nicht definiert werden, so dass es nicht einen Körper hat. Hoffe, dass ich die Sache klar könnte ein wenig nach oben.

Andere Tipps

Denken Sie daran, auf diese Weise an, dass Sie eine Reihe von Funktionen haben:

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

Wenn Sie nun diese nennen, welche Funktion aufgerufen wird?

int a[2];
array_size(a);  

Wenn Sie nun das Arraysize templatize erhalten Sie:

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

Der Compiler wird versuchen, eine Version von ARRAY_SIZE zu instanziiert, die Parameter übereinstimmt, was Sie nennen es mit. Also, wenn Sie es mit einer Reihe von 10 ints nennen, wird es instanziiert ARRAY_SIZE mit n = 10.

Als nächstes wird nur die Art templatize, so können Sie es nennen mit mehr als nur Arrays int:

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

Und du bist fertig.

Bearbeiten : Eine Notiz über die (&)

Die Klammern werden um das & benötigt zwischen Array von int Referenzen (illegal) und Verweise auf Array von ints zu unterscheiden (was Sie wollen). Da der Vorrang von [] höher als &, wenn Sie die Erklärung haben:

const int &a[1];

wegen Operator Vorrang, am Ende mit einer Ein-Element-Array von const Referenzen bis int. Wenn Sie die & zuerst angewendet werden soll, müssen Sie diese Kraft mit Klammern:

const int (&a)[1];  

Nun ist die Sie haben eine konstante Referenz auf ein ein Element Array von ints. In der Funktion Parameterliste, brauchen Sie nicht den Namen eines Parameters angeben, wenn Sie es nicht verwenden, so können Sie den Namen fallen, aber halten die Klammern:

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

Es geschieht nichts, mit dem Array. Es ist ein nicht verwendeter Parameter, der verwendet wird, um die Signatur der Template-Funktion zu lösen.

Es kann auch nicht als Template-Argument verwendet werden, aber das ist eine separate nit.

Eine wenig seltsame Art und Weise das Ergebnis als Kompilierung-const für die von uns zu erhalten, die nicht „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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top