Friday, May 15, 2015

C++11: Իտերացիա ֆայլային հոսքով

Բազմաթիվ ընթերցողների խնդրանքով այս
գրառումը նվիրում եմ Քիմ Քարդաշյանին։


C++11 լեզվում ներմուծված է նոր `for` հրամանը (range-based for loop), որը հնարավորություն է տալիս իտերացիա կատարել օբյեկտի `begin()`֊ից `end()` միջակայքում։ Օգտագործելով այդ `for` հրամանը, ուզում եմ հերթականությամբ թվարկել `ifstream` հոսքի նիշերը։ Ավելի պարզ ասած՝ ուզում եմ գրել այսպիսի մի կոդ․
// ...
std::ifstream inp(name);
// ...
for( char c : obj )
    std::cout << c;
// ...
Որտեղ `obj`-ը պիտի ստացվի `inp`֊ի հետ ինչ֊որ մանիպուլյացիաների արդյունքում։

Նոր `for` հրամանն օգտագործելու համար նրան տրվող օբյեկտը (որով պետք է իտերացիա կատարվի), պետք է ունենա `begin()` և `end()` մեթոդները։ Մի քիչ քչփորելուց հետո պատրաստեցի `IterableFile` դասը, որն ընդլայնում է `ifstream`-ը՝ ավելացնելով ֆայլի սկզբի հետ կապված իտերատորը վերադարձնող `begin()` մեթոդը և դատարկ իտերատոր վերադարձնող `end()` մեթոդը։
class IterableFile : public std::ifstream {
public:
  IterableFile( const char* name )
    : std::ifstream{name}
  {
    // պահպանել բացատանիշերը
    unsetf(std::ios_base::skipws); 
  }
  std::istream_iterator<char> begin()
  {
    // սկսել ֆայլի սկզբից
    clear(); seekg(0, std::ios::beg);
    return std::istream_iterator<char>(*this);
  }
  const std::istream_iterator<char> end()
  {
    return std::istream_iterator<char>();
  }
};
`IterableFile` դասի նմուշն արդեն կարելի է օգտագործել `for` իտերատորի մեջ, օրինակ, այսպես․
  IterableFile fin("ex0.cpp");

  for( char c : fin )
    std::cout << c;

  fin.close();
Շատ հարմար կլիներ, եթե նույն էֆեկտը ստանայի առանց նոր դաս գրելու, միայն STL֊ի հնարավորություններով, բայց կարծես թե դա չի ստացվում։ (Հաստատ չեմ կարող ասել։)