@sunefred: faktum är att man skulle kunna göra något som är väldigt likt den for-loop med iteratorn även i C
#include <stdio.h>
typedef int * int_iterator;
#define begin(arr) (arr)
#define end(arr) ((arr) + sizeof (arr) / sizeof (*arr))
int main()
{
int nums[] = { 1, 1, 2, 3, 5, 7 };
for (int_iterator it = begin(nums); it != end(nums); ++it) {
printf("%d\n", *it);
}
}
Men det är faktiskt inte så det fungerar i C++11 då STL bygger på överlagring av begin()/end() beroende på typ man skickar in. När man ändrade begin()/end() från att vara medlemsfunktioner på någon form av klass till att i stället använda C++ brutalt kraftfulla template mekanism öppnade sig en rad nya möjligheter.
Vi vill alltså att begin()/end() fungerar ungefär som i C-varianten ovan, men det måste vara en lösning som inte bygger på preprocessorn (den saknar de möjligheter till överlagring vi behöver).
Lösningen kommer behöva template då vi vill göra en specialisering för just C-arrayer. Vidare behöver vi kunna hantera arrayer av olika typer och av olika storlek, låter väldigt mycket som det då behövs två template argument, typen på elementen i arrayen och längden på arrayen. begin() ska returnera första elementet och end() ska returnera adressen till en efter sista elementet
template<typename ElemType, size_t ArrayLen>
ElemType * begin(...)
{
...
}
Det luriga nu är vad ska man använda som argument? Tja, vad är typen på en array givet de template argument som valdes här? Det ska vara array med element av typen ElemType av storlek ArrayLen. Vi vill också ta en referens till denna array, inte göra en kopia så måste få in & operatorn
template<typename ElemType, size_t ArrayLen>
ElemType * begin(ElemType (&anArray)[ArrayLen])
{
return anArray;
}
template<typename ElemType, size_t ArrayLen>
ElemType * end(ElemType (&anArray)[ArrayLen])
{
return anArray + ArrayLen;
}
Detta fungerar när det används så här
int nums[] = { 1, 1, 2, 3, 5, 7 };
for (auto it = begin(nums); it != end(nums); ++it) {
std::cout << *it << std::endl;
}
därför att enda möjliga funktionen för begin()/end() är de vi definierat ovan. Typen på vår array är int[6], vilket betyder att enda sättet kompilatorn kan få ihop det är genom att sätta ElemType till int och ArrayLen till 6.
Template i C++ är komplicerat, men det riktigt värdefulla är att man inte alls behöver förstå detaljerna i hur templates fungerar för att kunna använda dem. Man måste däremot ha örnkoll på detaljerna om man ger sig på att skriva egna templates.