Boost/Alkioiden läpikäynti

Säiliön alkioiden läpikäynti on yksi toistuvimmista ohjelmointi-idiomeista, mutta C++:n for-lauseella se on kovin hankalaa. Uudemmissa ohjelmointikielissä, kuten Javassa ja C#:ssa, siihen on oma foreach-lauseensa. Boostissa on sitä muistuttava makro BOOST_FOREACH.

Ongelma

muokkaa

C++:ssa on vaikeaa ja virhealtistakin läpikäydä säiliön alkiot for-lauseella. Seuraava on väärin, sillä int ei välttämättä riitä esittämään kaikkia säiliön indeksejä:

// mitä jos vec.size() > std::numeric_limits<int>::max()?
for (int i = 0; i < vec.size(); ++i) {
    std::cout << vec[i];
}

Seuraava on oikein ja vastaava toimii vektoreiden lisäksi myös muilla säiliöillä:

for (std::vector<char>::iterator i = vec.begin(); i != vec.end(); ++i) {
    std::cout << *i;
}

On kuitenkin huonoa tyyliä määritellä jonkin säiliön tyyppi useammassa kuin yhdessä paikassa, koska tällöin sitä on vaikeampi vaihtaa jälkeenpäin. Niinpä usein luodaan alias oikealle tyypille:

typedef std::vector<char> CharContainer;
CharContainer cc;
...
for (CharContainer::iterator i = cc.begin(); i != cc.end(); ++i) {
    std::cout << *i;
}

On selvää, että tällainen ratkaisu on hidas kirjoittaa ja lukea.

Ratkaisu

muokkaa

Boostissa on helppokäyttöinen makro säiliön alkioiden läpikäyntiin:

#include <boost/foreach.hpp>
...
BOOST_FOREACH (char c, cc) {
    std::cout << *c;
}

Se on selkeämpi lukea ja helpompi kirjoittaa kuin perinteinen C++-vastineensa.

Huomioitavaa

muokkaa

Tulee muistaa, että BOOST_FOREACH on vain makro. Seuraava koodi ei käänny, koska makro luulee pilkun olevan väärässä paikassa:

BOOST_FOREACH (std::pair<int, char> p, map) {
    std::cout << p.first << "," p.second << std::endl;
}

Ratkaisu on luoda alias:

typedef std::pair<int, char> IntCharPair;

Vaihtoehtoisesti voi suosiolla käyttää perinteistä läpikäyntitapaa.

Lähteet

muokkaa