C++ оператор istream ››

У меня проблема с моим оператором >>

istream& operator>> (istream& is, Matrix& M) {

    char first;

    is>>first;


    for(int i = 0;i<M.rows();i++) {

        for(int j = 0;j<M.cols();j++) {

            is>>M[i][j];
            cout<<M[i][j];

        }

        is>>first;

    }

    return is;
}

Я хочу размер оператора istream, потому что я хочу изменить циклы for, чтобы они не зависели от матрицы, которая была отправлена, т.е. вы отправляете матрицу с размером 1 и поток [1 2 3 4; 4 5 6 7; 1 2 3 4], затем новую матрицу с размером (3 * 4) должен быть построен. так что я могу использовать оператор присваивания, чтобы присвоить его матрице M.

Другими словами, поток находится в форме "[ 1 2 3; 2 3 4; 4 5 6]" и ; означает новую строку. Я хочу знать, сколько строк и столбцов есть.


person shizzle    schedule 22.12.2011    source источник


Ответы (4)


Вы можете получить все строки следующим образом:

vector<string> rows;
string line;

is.ignore(INT_MAX, '['); // ignores all characters until it passes a [

while (std::getline(is, line, ';'))
    rows.push_back(line); // put each row in rows

rows.back().erase(rows.back().find(']')); // erase the ending ]

Теперь у вас есть каждая строка строки в rows, затем

for (size_t i = 0; i < rows.size(); ++i) {
    vector<int> items;
    istringstream strstm(rows[i]);

    std::copy(istream_iterator<int>(strstm), istream_iterator<int>(), back_inserter(items));

    // now items is full of the entries, resize the matrix to hold items.size()
    // many items and insert each one into it, or whatever
}
person Seth Carnegie    schedule 22.12.2011
comment
Я получаю эту ошибку: переменная ‘std::istringstream strstm’ имеет инициализатор, но неполный тип - person shizzle; 22.12.2011
comment
@shizzle: Вам нужно #include <sstream>. - person Mike Seymour; 22.12.2011

Во-первых, конечно, вам нужно указать вещи немного строже, чем у вас есть. Что делать с чем-то вроде "[ 11 12 13; 21 22; 31 32 33 ]", например: вставить 0.0 вместо отсутствующего значения или установить failbit?

Кроме того, использование std::vector для сбора входных данных немного упростит задачу. Что-то вроде следующего, например:

template< typename T >
char getRow( std::istream& source, std::vector<T>& dest )
{
    dest.clear();
    char separator;
    source >> separator;
    while ( source && separator != ';' && separator != ']' ) {
        source.unget();
        T tmp;
        source >> tmp;
        if ( source ) {
            dest.push_back( tmp );
            source >> separator;
        }
    }
    if ( source && dest.empty() ) {
        dest.setstate( std::ios_base::failbit );
    }
    return source ? separator : '\0';
}

template< typename T >
char getFirstRow( std::istream& source,
                  std::vector<std::vector<T> >& dest )
{
    dest.clear();
    std::vector<T> row;
    char separator = getRow( source, row );
    if ( source ) {
        if ( row.empty() ) {
            dest.setstate( std::ios_base::failbit );
        } else {
            dest.push_back( row );
        }
    }
    return source ? separator : '\0';
}

template< typename T >
char getFollowingRow( std::istream& source,
                 std::vector<std::vector<T> >& dest )
{
    std::vector<T> row;
    char separator = getRow( source, row );
    if ( source ) {
        if ( row.size() != dest.front().size() ) {
            dest.setstate( std::ios_base::failbit ) ;
        } else {
            dest.push_back( row );
        }
    }
    return source ? separator : '\0';
}

template< typename T >
std::istream&
operator>>( std::istream& source, Matrix<T>& dest )
{
    char separator;
    source >> separator;
    if ( separator != '[' ) {
        source.setstate( std::ios_base::failbit );
    } else {
        std::vector<std::vector<T> > results;
        separator = getFirstRow( source, results );
        while ( separator == ';' ) {
            separator = getFollowingRow( source, results );
        }
        if ( separator != ']' ) {
            source.setstate( std::ios_base::failbit );
        }
        if ( source ) {
            dest.assign( results );
        }
    }
    return source;
}

Конечно, это означает, что функция Matrix<T>::assign должна иметь возможность устанавливать размеры. И чтобы его можно было использовать, Matrix<T> нужен конструктор по умолчанию, который, вероятно, «откладывает» фактическое построение до Matrix<T>::assign.

Кроме того: мы несколько ограничены в приведенном выше ограниченными возможностями для отчетов об ошибках в iostreams. В частности, нам бы очень хотелось различать ввод типа "[11 12 13; 21" и ничего (настоящее условие конца файла). Но наши попытки прочитать разделитель после "21" будут устанавливать eofbit, и мы ничего не можем с этим поделать. (На самом деле мы могли создать новое слово состояния, используя std::ios_base::xalloc(), устанавливая его тогда и только тогда, когда чтение '[' в начале завершается ошибкой с установленным eofbit. Но для этого потребуется очень нестандартный способ проверка на наличие ошибок в клиентском коде, что, в свою очередь, создало бы бесконечный поток проблем с обслуживанием.)

Наконец, два мета-комментария: если это кажется сложным... так оно и есть. Ввод почти всегда сложен из-за множества различных условий ошибки, которые вы должны проверить. И, во-вторых, обратите внимание на использование функций для упрощения каждой отдельной операции. Частой ошибкой новичков является то, что они не разбивают такие вещи на части. Это почти всегда плохое программирование, например, наличие вложенного цикла в функции, за исключением случаев применения математических алгоритмов к таким вещам, как Matrix. В этом случае синтаксический анализ не является математическим алгоритмом, и вы хотите отделить обработку каждой строки от общей обработки; в этом случае также полезно отделить обработку первой строки от остальных, поскольку случаи ошибок различны. (Первая строка может иметь любую длину больше 0, последующие строки должны иметь ту же длину, что и предыдущие строки.)

person James Kanze    schedule 22.12.2011

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

person Björn Pollex    schedule 22.12.2011

Невозможно определить «размер оператора istream», так как это, ну, поток, и когда вы читаете первый элемент матрицы, никто не может гарантировать, что последний элемент уже существует. Вы должны сначала прочитать всю строку, а затем разобрать ее и извлечь информацию о размере входной матрицы. После этого вы можете использовать свой код, передав ему эту строку через stringstream. Конечно, вы должны иметь возможность динамически изменять размер матрицы.

person aland    schedule 22.12.2011