Zastanawiam się, dlaczego ten rodzaj kodu może uzyskać rozmiar tablicy testowej? Nie znam gramatyki w szablonie. Może ktoś mógłby wyjaśnić znaczenie kodu pod template<typename,size_t>
. Poza tym preferowany jest również link referencyjny.
#define dimof(array) (sizeof(DimofSizeHelper(array)))
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
void InitDynCalls()
{
char test[20];
size_t n = dimof(test);
printf("%d", n);
}
c++
visual-c++
Cień diabeł
źródło
źródło
std::array
lubstd::vector
...Odpowiedzi:
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++
iC
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 wC
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: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:
Zauważ, że tablica
x
jest zadeklarowana , ale nie zdefiniowana . Aby wywołać z nim funkcję (tj.ArraySize
),x
Należy ją zdefiniować .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.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ą naN
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.
źródło
DimofSizeHelper
to funkcja szablonu, która pobieraT(&)[N]
parametr - aka odwołanie do tablicy C N elementów typuT
i zwracachar (&)[N]
aka referencję do tablicy N znaków. W C ++ char jest bajtem w przebraniu isizeof(char)
gwarantuje, że będzie1
zgodny ze standardem.n
ma przypisany rozmiar typu zwracanegoDimofSizeHelper
, czylisizeof(char[N])
który jestN
.To jest trochę skomplikowane
i niepotrzebne. Zwykłym sposobem na to było:Od C ++ 17 jest to również niepotrzebne, ponieważ mamy to,
std::size
co robi, ale w bardziej ogólny sposób, będąc w stanie uzyskać rozmiar dowolnego kontenera w stylu stl.Jak wskazał BoBTFish, jest to konieczne w przypadku krawędzi.
źródło
std::extent
od C ++ 11, który jest czasem kompilacji.