Страница 4 из 4
Но вот незадача: этот код не компилируется. Дело в том, что pos_type должен уметь конструироваться из нескольких заранее определенных типов(как показало исследование, 2). Базовые типы этого делать не умеют, так что придется написать свой собственный класс. Я не буду заострять внимание на этом классе, так как статья немного не на эту тему. Я просто приведу реализацию этого класса, а если у вас будут какие-то вопросы, то писать либо здесь, либо в PM. Итак, вот код: // пространство имен, в которое заносятся детали реализации namespace detail { template <typename num_type, typename state_type = std::mbstate_t> class pos_type_t { typedef pos_type_t<num_type, state_type> my_type;
num_type m_pos; state_type m_state;
static state_type initial_state;
public: // конструкторы pos_type_t(std::streampos off) : m_pos(off), m_state(initial_state) {} pos_type_t(num_type off = 0) : m_pos(off), m_state(initial_state) {} pos_type_t(state_type state, num_type pos) : m_pos(pos), m_state(state) {}
// получение состояния потока state_type state() const { return(m_state); }
// установка состояния потока void state(state_type st) { m_state = st; }
// получение позиции num_type seekpos() const { return(m_pos); }
// оператор преобразования operator num_type() const { return(m_pos); }
// далее идут операторы, которые осуществляют арифметические операции
num_type operator- (const my_type& rhs) const { return(static_cast<num_type>(*this) - static_cast<num_type>(rhs)); }
my_type& operator+= (num_type pos) { m_pos += pos; return(*this); }
my_type& operator-= (num_type pos) { m_pos -= pos; return(*this); }
my_type operator+ (num_type pos) const { my_type tmp(*this); return(tmp += pos); }
my_type operator- (num_type pos) const { my_type tmp(*this); return(tmp -= pos); }
// операторы сравнения
bool operator== (const my_type& rhs) const { return(static_cast<num_type>(*this) == static_cast<num_type>(rhs)); }
bool operator!= (const my_type& rhs) const { return(!(*this == rhs)); } }; //--------------------------------------------------- // статическая константа, которая обозначает начальное состояние template <typename num_type, typename state_type> state_type pos_type_t<num_type, state_type>::initial_state; } //--------------------------------------------------- // наконец-то наш класс свойств: template <typename char_t, typename long_pos_t> struct long_pointer_traits : public std::char_traits<char_t> { // определение pos_type через наш только что написанный класс typedef detail::pos_type_t<long_pos_t> pos_type;
// определение off_type через тип, переданный во 2 аргументе шаблона typedef long_pos_t off_type; }; //--------------------------------------------------- // вводим тип "длинного" файла typedef std::basic_ifstream<char, long_pointer_traits<char, __int64> > long_ifstream;
// используем long_ifstream для получения размера файла
| ОК, теперь все компилируется и работает. Но кроме получения позиции в файле, нам обычно надо работать еще с этими файлами(читать, писать). И, конечно, нам приходится работать со строками. Тогда если мы попытаемся считать строку из файла таким образом: long_ifstream infile(strFileName, std::ios::binary); std::string res; std::getline(infile, res);
| То мы получим ошибку компиляции. Проблема в том, что std::string - это "всего лишь" typedef от std::basic_string. Этот класс принимает 2 параметра шаблона: первый - тип для представления символа, а второй(как вы уже, наверное, догадались) - traits. Так вот, для корректной работы нам надо определить и свой тип строки: // "длинные" типы: typedef std::basic_ifstream<char, long_pointer_traits<char, __int64> > long_ifstream; typedef std::basic_string<char, long_pointer_traits<char, __int64> > long_string;
long_ifstream infile(strFileName, std::ios::binary); long_string res; std::getline(infile, res);
| Теперь все работает прекрасно. Таким образом, для правильного взаимодействия компонентов стандартной библиотеки нам придется определять нужные типы и работать с ними. К сожалению, на данный момент я не знаю способа, как можно было бы создать нужный тип для стандартных потоков ввода/вывода(cin, cout, cerr, clog). Так что чтобы вывести такую "длинную" строку на экран, надо будет написать свой оператор вывода такой строки. Другого решения мне неизвестно(если кто-то знает - поделитесь, буду признателен). Также хочу сказать несколько слов о совместимости и переносимости: приведенный мной код по определению размера большого файла был проверен на компиляторах VC7.1 и Intel C++ 8.0. Использовалась стандартная библиотека, которая идет по умолчанию с VC. При работе с ней замечено никаких ошибок не было. Проверялся код и с использованием STLPort версий 4.6.2 и 5.0. Компилировался он без проблем, но работал неправильно. Надеюсь, в дальнейших версиях STLPort'а это будет исправлено и работать будет корректно, так как данный код соответствует стандарту. |