« předchozí článek | obsah čísla | následující článek »
V této pravidelné rubrice se budete dozvídat o tajuplných zákoutích podivuhodného multiparadigmatického programovacího jazyka C++. Rubrika předpokládá dobrou znalost tohoto jazyka, takže pokud nemáte tušení, za jakých okolností se pole automaticky konvertuje na ukazatel na svůj první prvek, tato rubrika nebude pro vás. Pokud se to chcete dozvědět, mohu doporučit knihu Jazyky C a C++ : kompletní průvodce, jejímž autorem je Miroslav Virius.
Dnes poodhalíme tajemství polí a jejich rozměrů. V řadě učebnic najdete radu uschovat si rozměr pole do celočíselné konstanty:
const int pole_rozmer = 4;
int pole[pole_rozmer] = {1, 2, 3, 4};
Toto řešení má ale dvě nevýhody. Především si musíte zapamatovat název pomocné konstanty. Větší problém ovšem nastane, když se rozhodnete nechat si rozměr pole odvodit podle počtu inicializátorů:
int pole[] = {1, 2, 3, 4};
V tomto případě je totiž uvedené řešení nepoužitelné. První další řešení, které většinu programátorů napadne, je následující použití operátoru sizeof
:
sizeof(pole) / sizeof(int)
Není to úplně špatná myšlenka, ale má další dva nedostatky. Předně když se rozhodnete změnit typ prvku pole například na double
, začne uvedený výraz dávat chybné výsledky. Tento nedostatek lze odstranit drobnou úpravou:
sizeof(pole) / sizeof*(pole)
Oba uvedené výrazy jsou ovšem náchylné k chybnému použití. Například:
int funkce(char pole[20]) // pozor, není pole!
{
return sizeof(pole) / sizeof*(pole);
}
Uvedená funkce téměř jistě nevrátí číslo 20, ale spíš 4, nebo 8. Její parametr je totiž navzdory syntaxi ukazatel, ne pole.
Jednoduché, bezpečné a rozšiřitelné řešení nabízejí šablony:
template<typename T, size_t SZ>
struct pole_type {
typedef T type[SZ];
};
template<typename T, size_t SZ>
typename pole_type<char, SZ>::type &arraydim(
T (&)[SZ]) throw ();
Funkce arraydim() transformuje libovolné pole na referenci na pole znaků o stejné dimenzi. A protože podle standardu sizeof(char) == 1
, můžeme nyní dimenzi pole zjistit výrazem:
sizeof arraydim(pole)
Mechanismus šablon zajišťuje statickou typovou kontrolu a přetížením funkce arraydim() můžeme její funkcionalitu rozšířit o podporu dalších typů, například bitových sad:
template<size_t SZ>
typename pole_type<char, SZ>::type &arraydim(
const std::bitset<SZ> &) throw ();
Protože funkci arraydim() budeme používat jen uvnitř operátoru sizeof
, nemusíme definovat její tělo, což ušetří práci kompilátoru, protože ji nebude muset kompilovat. Konstrukci sizeof arraydim
pak můžeme zabalit do makra preprocesoru, ale to už nechám na vás.
A malý vtip na závěr:
for (size_t i = 8; i >= 0; --i)
printf("Shall I end? Nevermore!\n");