QL.túra

Kulturális smörgåsbord Esterházytól Wass Albertig, a gumicsizmától az iPad-ig, a Teletabiktól Sexpírig, a makrofágtól a mikrokontrollerig, miazmás...

Címkék

2000 (20) 2001 (6) 2002 (16) 2003 (164) 2004 (61) 2005 (40) 2006 (31) 2007 (28) 2008 (33) 2009 (175) 2010 (188) 2011 (201) 2012 (86) 2013 (40) 2014 (36) 2015 (26) 2016 (10) adáshiba (91) android (1) animáció (93) cygwin (3) film (410) gezarol (13) hájtek (159) hangoskönyv (32) ipad (17) klip (12) könyv (191) linux (29) színház (169) vers (17) windows (37) zene (111) Címkefelhő

+jegyzések

Most ...

... múlok .osan

bmi_tiny.png


... hallgatom
Szabó Magda: Régimódi történet
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSqTmZEqlCRFgojyt52Q2n_qiMTyVlt-zJu-DpbNKVY6OQbBh4u


... olvasom
Alexander Steele (szerk.): Kezdő írók kézikönyve


... (Kik ezek? Kik ezek az embek? Kik ezek?)
profile for TrueY on Stack Exchange, a network of free, community-driven Q&A sites
free counters

[Hájtek] Visual Studio 2010: egyszerűsített iteráló ciklus C++-ban

2011.06.03. 12:00 | TrueY | Szólj hozzá!

Címkék: windows linux 2011 hájtek

http://www.microsoft.com/visualstudio/_base_v1/images/promos/upgrade_VS.pngSűrűn előforduló esemény, hogy C++-ban egy lista elemein kell végiglépkedni egy ciklusban. A for_each egy jó megoldás lenne, de ahhoz mindig egy függvényt kell definiálni, amit a for_each majd jól meghív. C++-ben viszont nincs anonymous függvény, mint Perl-ben, vagy nem lehet függvényen belül függvényt definiálni, mint Pascal-ban. Egy class-on belüli class definíció még lehetséges lenne, ami implementálja a () operátort, de az csúnyán megtördeli a kódot.

A C++0x kiterjesztésben találtam erre nézvést törekvéseket. Visual Studio-ban vannak C++0x-es megoldások. Rá is leletem a decltype() függvényre, amivel fordítási időben vissza tudjuk kapni az adat típusát. Nézzük meg, hogy mit lehet ezzel kezdeni?

Szóval a probléma:

list<CType> List;

//...

for(list<CType>::iterator iter = List.begin();
    iter !=   List.end(); ++iter )
{
//...
}

Hogyan lehet ezt egyszerűsíteni? Az lenne a legjobb, ha csak a List-et kellene megadnom és abból kitalálná, hogy milyen iterátor-t kell használni. Valami makróban gondolkodtam, hogy ne kelljen függvényt átadni paraméterként.

Az első lehetőség ez lenne:

#define FOREACH(_Iter, _Type, _Container) \
  for(list<_Type>::iterator _Iter = _Container.begin(); \
      _Iter != _Container.end(); ++_Iter)

De itt "feleslegesen" meg kell adni a List elemeinek típusát, amit a fordító már ismer. További gond, hogy minden konténer osztályra külön kell egy ilyet definiálni. Na, pont erre van a decltype() függvény.

#define FOREACH(_Iter, _Container) \
  for(decltype(_Container.begin()) _Iter = _Container.begin(); \
      _Iter != _Container.end(); ++_Iter )

Egy még régebbi g++-szal (4.1.2) próbálkoztam és nem működött. Ott a decltype helyett még __typeof__ ment.

#define FOREACH(_Iter, _Container) \
  for(__typeof__(_Container.begin()) _Iter = _Container.begin(); \
      _Iter != _Container.end(); ++_Iter )

Ez már szépen megoldja mind a két problematikát! Pár perces keresgélés után találtam még egy érdekességet. Ez az auto "típus", amit VS 2010-ben az MS szintén átvett a C++0x-ből. Az auto típust pontosan ugyanúgy használhatjuk, mint bármelyik egyszerű, vagy összetett típust. Az értékadás eredményének típusa lesz a deklarált változó típusa. Tehát a

#define FOREACH(_Iter, _Container) \
  for(auto _Iter = _Container.begin(); _Iter != _Container.end();
      ++_Iter )

pont azt csinálja, amit szeretnék. Használata:

list<CType> List;

//...

FOREACH(iter, List)
{
    //... az iter nevű iterátort lehet használni
}

Mondjuk ettől a kódunk nem biztos, hogy hordozható lesz. Bár én azt látom, hogy a 4.x-es gcc már tudja a C++0x dolgokat (egy példa) (x valszeg > 1). Nekem VS2010 alatt nem ment a decltype(List)::iterator, de az előző cikk szerint a gcc 4.6 óta már tudja.

Ebből csinálhatunk olyan ciklust is, amit const_terator-t használ. Ehhez egy kicsit még trükközni kell, mert a régi C++-ban nincs cbegin(), amit egyből a megfelelő típusú iterator-t ad vissza:

template <class T>
struct IterType { typedef typename T::const_iterator citer_t; };

#define FOREACHCONST(_CIter, _Container) \
  for(IterType<typeof(_Container)>::citer_t _CIter = _Container.begin(); \
      _CIter != _Container.end(); ++_CIter )

A C++0x szerint még egyszerűbben is megoldhatjuk a fenti dolgot (Range-based for-loop) minden olyan esetben, amikor a tároló objektum támogatja az iterátorokat. Sajna ezt a VS2010 nem támogatja, pedig milyen szép is ez!

int my_array[5] = {1, 2, 3, 4, 5};
for (int &x: my_array) { x *= 2;}

Hoppácska! A C++0x már tud lambda függvényeket (l. perl anomymous functions)! Tud ilyen a VS2010? Úgy látom, hogy igen! Leírás >itt<. Ezt a lambda függvényt megadhatjuk a for_each harmadik paramétereként! Nattyon kúl!

Iteráljunk minden nap!

A bejegyzés trackback címe:

https://qltura.blog.hu/api/trackback/id/tr602946049

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása