To jest naprawdę trudne do wyjaśnienia, ale spróbuję ...
Po pierwsze, dimof
informuje o wymiarze lub liczbie elementów w tablicy. (Uważam, że „wymiar” jest preferowaną terminologią w środowiskach programistycznych Windows).
Jest to konieczne, ponieważ C++
i C
nie daje natywnego sposobu określania rozmiaru tablicy.
Często ludzie zakładają, sizeof(myArray)
że zadziała, ale w rzeczywistości da ci rozmiar pamięci, a nie liczbę elementów. Każdy element prawdopodobnie zajmuje więcej niż 1 bajt pamięci!
Następnie mogą spróbować sizeof(myArray) / sizeof(myArray[0])
. Dałoby to rozmiar w pamięci tablicy podzielony przez rozmiar pierwszego elementu. Jest ok i szeroko stosowany w C
kodzie. Głównym problemem jest to, że wydaje się działać, jeśli przekażesz wskaźnik zamiast tablicy. Rozmiar wskaźnika w pamięci zwykle wynosi 4 lub 8 bajtów, nawet jeśli wskazuje na tablicę zawierającą 1000 elementów.
Następną rzeczą do wypróbowania C++
jest użycie szablonów, aby wymusić coś, co działa tylko dla tablic i da błąd kompilatora na wskaźniku. To wygląda tak:
template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"
Szablon będzie działał tylko z tablicą. Wyliczy typ (nie jest tak naprawdę potrzebny, ale musi tam być, aby szablon działał) i rozmiar tablicy, a następnie zwróci rozmiar. Sposób pisania szablonu nie może działać ze wskaźnikiem.
Zwykle możesz się tutaj zatrzymać, a jest to w standardowej wersji biblioteki C ++ jako std::size
.
Ostrzeżenie: poniżej trafia na owłosione terytorium prawnika języka.
Jest to całkiem fajne, ale nadal nie działa w przypadku niejasnej krawędzi:
struct Placeholder {
static float x[8];
};
template <typename T, int N>
int ArraySize (T (&)[N])
{
return N;
}
int main()
{
return ArraySize(Placeholder::x);
}
Zauważ, że tablica x
jest zadeklarowana , ale nie zdefiniowana . Aby wywołać z nim funkcję (tj. ArraySize
), x
Należy ją zdefiniować .
In function `main':
SO.cpp:(.text+0x5): undefined reference to `Placeholder::x'
collect2: error: ld returned 1 exit status
Nie możesz tego połączyć.
Kod, który masz w pytaniu, pozwala to obejść. Zamiast faktycznie wywoływać funkcję, deklarujemy funkcję, która zwraca obiekt o dokładnie odpowiednim rozmiarze . Następnie wykorzystujemy sizeof
sztuczkę.
To wygląda jak nazywamy funkcję, ale sizeof
jest czysto czas kompilacji konstrukt, więc funkcja nigdy nie jest wywoływana.
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
^^^^ ^ ^^^
// a function that returns a reference to array of N chars - the size of this array in memory will be exactly N bytes
Zauważ, że faktycznie nie możesz zwrócić tablicy z funkcji, ale możesz zwrócić odwołanie do tablicy.
Następnie DimofSizeHelper(myArray)
jest wyrażenie, którego typ jest tablicą na N
char
s. Wyrażenie tak naprawdę nie musi być dostępne, ale ma sens w czasie kompilacji.
Dlatego sizeof(DimofSizeHelper(myArray))
powie ci rozmiar w czasie kompilacji, co byś otrzymał, gdybyś faktycznie wywołał funkcję. Chociaż tak naprawdę nie nazywamy tego.
Nie martw się, jeśli ten ostatni blok nie miałby sensu. Dziwne jest obejście dziwacznej obudowy. Dlatego nie piszesz tego rodzaju kodu samemu i pozwalasz programistom bibliotek martwić się o tego rodzaju bzdury.
std::array
lubstd::vector
...