Как скопировать объекты из класса?
От: Аноним  
Дата: 19.07.10 08:17
Оценка:
Допустим класс содержит в себе контейнер объектов, причем, сам контейнером в узком смысле не является. Например -- класс, хранящий и выдающий дескрипторы открытых файлов, и предоставляющий дополнительные операции над ними. Как лучше предоставить средства для получения списка значений внутреннего контейнера?

Пример
class X {
public:
  typedef std::vector<std::string> container;
private:
  container c;
};


Можно выдать итераторы на начало и конец:
class X {
public:
  typedef std::vector<std::string> container;
  typedef container::iterator iterator;
  iterator begin() { return c.begin(); }
  iterator end() { return c.end(); }
  //и конст итераторы
private:
  container c;
};


Можно добавить функцию для копирования:
class X {
public:
  typedef std::vector<std::string> container;
  template <typename T> void copy(T out)
  {
    std::copy(c.begin(), c.end(), out);
  }
private:
  container c;
};


Есть еще подходы?
Что делать если внутренний контейнер не std::vector<std::string>, а std::map<int, Z>, где Z — структура, из которой мы хотим выдавать лишь одно поле, а не всю структуру? Для этого подходит второй способ, но функцию приходится определять сразу, то есть в hpp-файле. Есть какое нибудь стандартное решение?
Re: Как скопировать объекты из класса?
От: Кодт Россия  
Дата: 19.07.10 10:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Что делать если внутренний контейнер не std::vector<std::string>, а std::map<int, Z>, где Z — структура, из которой мы хотим выдавать лишь одно поле, а не всю структуру? Для этого подходит второй способ, но функцию приходится определять сразу, то есть в hpp-файле. Есть какое нибудь стандартное решение?


Поскольку объявление члена — container c — всё равно лежит в хедере, то не вижу препятствий, чтобы там же лежало и определение функции.
Оно несложное
  template<class OutIt>
  void copy(OutIt out)
  {
    std::transform(c.begin(), c.end(), out, theFieldOfZ);
  }
  // не хочу городить bind в ущерб читаемости
  static int justFieldOfZ(std::map<int,Z>::value_type const& elem)
  {
    return elem->second.theField;
  }
Перекуём баги на фичи!
Re[2]: Как скопировать объекты из класса?
От: Wody  
Дата: 19.07.10 11:17
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Поскольку объявление члена — container c — всё равно лежит в хедере, то не вижу препятствий, чтобы там же лежало и определение функции.

К>Оно несложное
К>
К>  template<class OutIt>
К>  void copy(OutIt out)
К>  {
К>    std::transform(c.begin(), c.end(), out, theFieldOfZ);
К>  }
К>  // не хочу городить bind в ущерб читаемости
К>  static int justFieldOfZ(std::map<int,Z>::value_type const& elem)
К>  {
К>    return elem->second.theField;
К>  }
К>


Спасибо, приятное решение. А как поступить если для X используется подход с разделением на интерфейс (абстрактный класс) и имплементацию?
Re[3]: Как скопировать объекты из класса?
От: Кодт Россия  
Дата: 19.07.10 14:19
Оценка:
Здравствуйте, Wody, Вы писали:

W>Спасибо, приятное решение. А как поступить если для X используется подход с разделением на интерфейс (абстрактный класс) и имплементацию?


Паттерн "Посетитель".

Заменить output iterator на функцию, например
class IX
{
  .....
  virtual void copyTo( boost::function<void(int)> output ) = 0;
};

......

void X::copyTo( boost::function<void(int)> output )
{
  std::for_each( c.begin(), c.end(), boost::bind(output, boost::bind(getTheField, _1)) );
  // или просто
  for(container::const_iterator i=c.begin(); i!=c.end(); ++i)
    output(i->second->theField);
}

А саму функцию несложно сконструировать из итератора
struct writer // всеядная функция - мономорфный тип с полиморфным оператором
{
  typedef void result_type;
  template<class I, class V> void operator()(I& i, V const& v) { *i++ = v; }
};

std::vector<long> vec; // заметим, что тип приёмника (long) не обязательно совпадает с типом источника (int)
x.copyTo( boost::bind(writer(), std::back_inserter(vec), _1) );
Перекуём баги на фичи!
Re[4]: Как скопировать объекты из класса?
От: Wody  
Дата: 19.07.10 16:24
Оценка:
Спасибо! То, что нужно.
Re[4]: Как скопировать объекты из класса?
От: Кодт Россия  
Дата: 19.07.10 20:59
Оценка:
К>А саму функцию несложно сконструировать из итератора
К>
К>struct writer // всеядная функция - мономорфный тип с полиморфным оператором
К>{
К>  typedef void result_type;
К>  template<class I, class V> void operator()(I& i, V const& v) { *i++ = v; }
К>};

К>std::vector<long> vec; // заметим, что тип приёмника (long) не обязательно совпадает с типом источника (int)
К>x.copyTo( boost::bind(writer(), std::back_inserter(vec), _1) );
К>


Погорячился: сперва back_inserter превращает push_back в итератор, а затем writer превращает его обратно в функцию.
Можно сократить
std::vector<long> vec;
x.copyTo( boost::bind(&std::vector<long>::push_back, &vec, _1) );
Перекуём баги на фичи!
Re: Как скопировать объекты из класса?
От: MasterZiv СССР  
Дата: 20.07.10 05:56
Оценка: 31 (1) +1
Аноним 552 wrote:

> Есть еще подходы?


Да.

2 функции (или 3)
функция, выдающая кол-во этих объектов
и функция (или 2), выдающая константную ссылку (и неконстантную) на N-ый объект.

Похоже что все рехнулись на этих контейнерах, итераторах и темплейтах.

> Что делать если внутренний контейнер не std::vector<std::string>, а

> std::map<int, Z>, где Z — структура, из которой мы хотим выдавать лишь
> одно поле, а не всю структуру?

Это дело реализации этого твоего класса, а не его интерфейса.

Для этого подходит второй способ, но
> функцию приходится определять сразу, то есть в hpp-файле. Есть какое
> нибудь стандартное решение?

Это вовсе не обязательно. Тебе не нужен шаблонный метод копирования,
тип данных в твоём массиве вполне конкретный.
Posted via RSDN NNTP Server 2.1 beta