Оператор перегрузки потока для вложенного шаблона C ++ STL - PullRequest
2 голосов
/ 12 сентября 2011

У меня есть файл данных, который представляет собой одну строку, состоящую из вложенной серии двойных чисел, например.

[[0.127279,0.763675,0.636396],[0.254558,0.890955,0.636396],
[0.127279,0.636396,0.763675],[0.254558,0.763675,0.763675],
[0.381838,0.890955,0.763675],[0.127279,0.509117,0.890955],
[0.254558,0.636396,0.890955],[0.509117,0.890955,0.890955]]

Я хотел бы иметь возможность прочитать это в STL vector<vector<double> >, используя оператор потока, который шаблонируется по внутреннему типу A:

vector<vector<double> > A;
FIN >> A;

Я нашел способ сделать это, когда вектор не является вложенным, т.е. простой vector<T> так:

template <class T>
istream& operator>>(istream& s, vector<T> &A){
  T x;
  string token; char blank;

  s >> blank; // Gobble the first '['
  while( getline(s, token, ',') ) {
   istringstream input(token);
   input >> x;
   A.push_back(x);
  }
  s >> blank; // Gobble the last ']'
  return s;
}

Но у меня проблема с istream& operator>>(istream& s, vector<vector<T> >&A), потому что я не могу понять, правильно ли внутренние ]. Я уверен, что у Boost есть способ сделать это, но я хотел бы увидеть решение с STL для педагогических целей.

Примечание: я знаю, что перегрузка оператора потока для vector<T> может иметь далеко идущие нежелательные последствия и что реализация должна быть обернута в свой собственный класс - я использую этот пример выше для пояснения вопрос.

EDIT: Мне бы хотелось, чтобы метод был достаточно устойчивым для обработки входного массива, размер (и размер внутреннего массива) которого равен , а не , заранее известному, но предполагаемому при чтении потока.

Ответы [ 3 ]

2 голосов
/ 12 сентября 2011

На самом деле проблема с вашим кодом в том, что вы хотите использовать одну и ту же функцию для обоих, когда T:

  • vector<double>
  • double

Но логика, которая должна считывать данные в vector и double , немного отличается. Таким образом, вы не можете сделать это, по крайней мере, с такой простой логикой:

Я бы предпочел написать две функции, чтобы обрабатывать оба случая отдельно. В конце концов, даже в вашем случае компилятор сгенерирует две разные функции для каждого значения T.

template <class T>
istream& operator>>(istream& s, vector<T> &A)
{
  T x;
  string token; char blank;

  s >> blank; // Gobble the first '['
  while( getline(s, token, ',') ) 
  {
   istringstream input(token);
   input >> x;
   A.push_back(x);
  }
// s >> blank; // Gobble the last ']'
  return s;
}

template <class T>
istream& operator>>(istream& s, vector<vector<T>> &A)
{
  vector<T> x;
  string token; 
  char blank;

  s >> blank; // Gobble the first '['
  while( getline(s, token, ']') ) 
  {
   istringstream input(token);
   input >> x;
   s >> blank; //read , after [...]
   A.push_back(x);
   x.clear();
  }
  s >> blank; // Gobble the last ']'
  return s;
}

Тестовый код:

int main() {
        vector<vector<double>> A;       
        cin >> A;
        for(size_t i = 0 ;i < A.size(); ++i)
        {
            for(size_t j = 0 ; j < A[i].size(); ++j)
                 cout << A[i][j] <<"   ";
            cout << endl;
        }
        return 0;
}

Введите:

[[1,2,3],[4,5,6],
[7,8,9],[10,11,12],
[13,14,15],[16,17,18],
[19,20,21],[22,23,24]]

Выход:

1   2   3   
4   5   6   
7   8   9   
10   11   12   
13   14   15   
16   17   18   
19   20   21   
22   23   24 

Онлайн демо: http://ideone.com/iBbmw

1 голос
/ 06 сентября 2016

Несколько лет спустя я столкнулся с той же проблемой.

На основании вашего вклада я разработал модифицированную версию оригинального шаблона.Этот способен анализировать многомерные массивы, даже если они распределены по нескольким строкам.

template <class T>
istream& operator>>(istream& s, vector<T> &A){
  while(true){
    T x;
    char c = s.peek();

    if( c == '[' || c == ','){ 
        s.ignore();
        if(s >> x) A.push_back(x);
        else throw invalid_argument("Bad, bad JS array!");
        continue;
    }

    if( c == ']') {
        s.ignore();
        return s;
    }

    /* Ignore line-break */
    s.ignore();     
  }
  return s;
}

Надеюсь, это кому-нибудь пригодится.

1 голос
/ 12 сентября 2011

В вашем конкретном примере, который очень прост.

  • Прочитать всю строку в строку.
  • Заменить все [,] и пробелами.
  • Создать простой поток строк с замененной пробелом строкой.

Теперь вы можете иметь простой цикл

double x;
while( stringstreamp >> x )
{
}

И какая-то особая логика после прочтения трех двойных, чтобы вставить их в новый массив.

...