Синтаксис потока для чтения из std :: vector (или другой последовательности)? - PullRequest
2 голосов
/ 29 июня 2011

Представьте, что у меня есть класс Variant, который может представлять различные типы POD, плюс std :: string, и у меня есть метод шаблона T get_value(const Variant&), который может извлекать из него базовые типы.

Предположим, у меня есть их вектор, т.е. std::vector<Variant> variants;, и я хочу прочитать несколько значений из него с удобным синтаксисом, например так:

int x;
double y;
std::string z;
// Get elements 0, 1, and 2 as int, double, and string respectively
streamlikeObject >> x >> y >> z;

Вопрос в том, что является хорошим способом для формирования гипотетического streamlikeObject в примере? Я могу представить себе создание собственного класса с оператором извлечения, но меня просто интересует, есть ли что-то в библиотеке std или, возможно, Boost, который обрабатывает подобные вещи.

Или альтернативно: как еще можно извлечь эти данные с аналогичной степенью краткости кода? Возможно, есть лучшая альтернатива синтаксису потока.

Ответы [ 4 ]

3 голосов
/ 29 июня 2011

Что-то вроде ( не проверено )

template <typename Iter>
class Extractor {
    Iter cur;
    Iter const &end;

  public:
    Extractor(Iter const &begin, Iter const &end)
      : cur(begin), end(end) { }

    template <typename T>
    Extractor &operator>>(T &x)
    {
        if (cur == end)
            throw SomeException();
        x = cur->get_value();
        ++cur;
        return *this;
    }
};

Построить с Extractor<std::vector<Variant>::const_iterator> streamlikeObject(v.begin(), v.end());.

В качестве альтернативы, если вы хотите извлечь только из контейнеров, вы можете захотеть параметризовать шаблон для типа контейнера вместо типа итератора для сохранения ввода (pardon pun).

1 голос
/ 29 июня 2011

Итак, позвольте мне убедиться, что я правильно понимаю.

У вас есть std :: vector, и он содержит произвольные данные.Содержимое которого определяется во время выполнения.

И вы хотите взять этот определенный во время выполнения объект и применить к нему последовательность времени компиляции следующим образом:

std::vector<Variant> >> val1 >> val2 >> val3;

Я полагаю, ваш кодпросто выдаст, если текущее значение не соответствует ожидаемому типу, да?

Вы можете использовать некоторые возможности Boost.IOStream для этого.В основном вы будете создавать новый тип потока, который использует ваши варианты вместо char.И вам понадобится потоковый буфер, который извлекает из (предположительно const) ссылку на контейнер этих Variant объектов.

0 голосов
/ 29 июня 2011

Если цель состоит в том, чтобы создать что-то общее, я, вероятно, попробую что-то с std::tuple, разрешив использование следующим образом:

std::tuple<int, double, std::string> input;
streamLikeObject >> input;

(Реализация оставлена ​​в качестве упражнения для читателя.)

0 голосов
/ 29 июня 2011

Примерно так:

struct A
{
  int a;
  float b;
  std::string c;
};

std::istream& operator>>( std::istream &is, const A &a )
{
  is >> a.a;
  is >> a.b;
  is >> a.c;
  return is;
}
...