Разработка оболочки итератора - PullRequest
4 голосов
/ 08 февраля 2010

Я написал класс, который упаковывает итератор и возвращает преобразованные значения по требованию:

// iterator-wrapper.h
template<class Iter, class Val, class Fct>
class IteratorWrapper {
  Iter cur_;
  const Iter last_;
  const Fct fct_;
public:
  IteratorWrapper(Iter first, Iter last, const Fct fct)
    : cur_(first), last_(last), fct_(fct) 
  {}
  const Val Value() const {return fct_(*cur_);}
  void Next() {++cur_;}
  bool Done() const {return cur_ == last_;}
};

Теперь класс может использовать его для возврата итераторов по некоторым функциям своих данных:

// mydata.h
#include <map>
#include "iterator-wrapper.h"

class MyData {

  struct GetFirst {
    template<class T1, class T2>
      const T1& operator()(const std::pair<T1,T2>& aPair) const {
      return aPair.first;
    }
  };
  struct GetSecond {
    template<class T1, class T2>
      const T2& operator()(const std::pair<T1,T2>& aPair) const {
      return aPair.second;
    }
  };

  typedef std::string Key;
  typedef int Val;
  typedef std::map<Key, Val> Map;
  typedef Map::const_iterator MapIter;
  Map m_;

public:

  typedef IteratorWrapper<MapIter, Key, GetFirst> KeysIter;
  typedef IteratorWrapper<MapIter, Val, GetSecond> ValuesIter;

  MyData() { // add some data
    m_["foo"] = 1;
    m_["bar"] = 2;
  }

  KeysIter GetKeys() const {
    return KeysIter(m_.begin(), m_.end(), GetFirst());
  }

  ValuesIter GetValues() const {
    return ValuesIter(m_.begin(), m_.end(), GetSecond());
  }
 };

И, вот пример использования:

#include <iostream>
#include "iterator-wrapper-data.h"

 int main() {
   MyData d;

   std::cout << "KEYS:" << std::endl;
   MyData::KeysIter kit = d.GetKeys();
   for(; !kit.Done(); kit.Next()){
     std::cout << kit.Value() << std::endl;
   }

   std::cout << "VALUES:" << std::endl;
   MyData::ValuesIter vit = d.GetValues();
   for(; !vit.Done(); vit.Next()){
     std::cout << vit.Value() << std::endl;
   }
   return 0;
 }

У меня есть несколько вопросов по этому поводу:

  1. Это разумный дизайн, или можно сделать его более кратко, возможно, используя STL или поддержку? (Я знаю, что есть boost::iterator_facade, но я нашел этот код более сложным, чем необходимо, и я не уверен, что он выполняет именно то, что я хочу здесь.)

  2. Почему std::map не содержит ничего подобного для начала (я имею в виду функцию keys(), которая возвращает итератор по ключам и т. Д.)? (Или это?)

  3. Что не так с возвратом ссылки, например const Val& Value() const (в отличие от возврата по значению, как в первом листинге выше)?

Ответы [ 3 ]

4 голосов
/ 08 февраля 2010

Вы были на правильном пути, взглянув на boost :: iterator_facade, но вам даже лучше с boost :: transform_iterator .

2 голосов
/ 08 февраля 2010

О вашем втором вопросе: библиотека Boost RangeEx ( zip-файл ) (еще не распространяемая с Boost, но принятая для будущего включения) содержит адаптеры диапазона для перебора ключей и значений карты:

int main() {

   std::map<int, std::string> m;
   m[1] = "one";
   m[2] = "two";

   std::cout << "KEYS:" << std::endl;
   BOOST_FOREACH(int k, m | boost::adaptors::map_keys) {
       std::cout << k << std::endl;
   }

   std::cout << "VALUES:" << std::endl;
   BOOST_FOREACH(std::string const & v, m | boost::adaptors::map_values) {
       std::cout << v << std::endl;
   }
   return 0;
}
1 голос
/ 08 февраля 2010

Это не кажется мне необоснованным, но я не думаю, что это действительно необходимо. Есть select1st и select2nd из SGI STL Guide :

int main()
{
  map<int, double> M;
  M[1] = 0.3;
  M[47] = 0.8;
  M[33] = 0.1;

  transform(M.begin(), M.end(), ostream_iterator<int>(cout, " "),
            select1st<map<int, double>::value_type>());
  // The output is  1 33 47.
}

О, и, конечно же, есть compose1 и compose2, когда вы хотите сделать больше, чем просто передать их в какой-либо итератор вставки или вывода напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...