Во-первых, конечно, вам нужно будет указать более строгие правила, чем вы.
иметь. Что вы должны сделать с чем-то вроде "[ 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, более поздние строки должны иметь одинаковую длину
как предыдущие строки.)