Всем привет! Думаю, что многие слышали, что в 2011 году вышел новый стандарт языка программирования c++. Возможности языка с новым стандартом существенно расширены, благодаря чему стало возможно делать довольно удобные вещи. Когда появляется что-то новое, то сразу хочется это попробовать на чем-нибудь полезным.
Проект testlib.hpp содержит реализацию библиотеки для разработки чекеров и генератов для олимпиадных задач. Идея разработать такую библиотеку совсем не новая, развитие множества таких библиотек происходит уже больше десяти лет. Такие библиотеки есть для огромного количества языков программирования. В России все начиналось с паскаля, потом появились библиотеки и для c++, python, java.
Зачем нужна еще одна библиотека? Затеяв разработку этой библиотеки, я преследовал множество целей.
- Первая цель была учебная. Эту библиотеку полностью разработали два человека: riadwaw и map. Мне кажется, что эта цель удалась. Ребятам потребовалось узнать много нового не только в языке c++ и его новом стандарте, но и в целом был получен полезный опыт общих принципов программирования.
- Второй целью была расширяемость. Под расширяемостью здесь я подразумеваю возможность добавлять функциональность без изменения кода библиотеки. Это принцип, который используется при создании всех общих библиотек и фраймворков.
- Реализация современных интерфейсов, принятых в языке c++. Поддержка совместимости с stl, поддержка stream интефейсов << и >>.
Если первая цель удалась, то что же получилось со второй и третьей я расскажу описанием самой библиотеки.
Начнем с простого примера:
#include "testlib.hpp"
TESTLIB_CHECK(){
verifyEqual(ouf.read<int>(), ans.read<int>());
OK("1 number");
}
Отличия от testlib.h на этом примере не столь существенны. Однако видно, что чтение реализовано шаблонной функцией. Возможно это не привычно, но позволяет расширять библиотеку.
Посмотрим еще один пример, в котором происходит считывание вектора. Приведено лишь два варианта, существуют и другие с указанием разделителей.
#include "testlib.hpp"
#include <vector>
using namespace std;
TESTLIB_CHECK(){
//Считывает вектор из n чисел, разделенных пробелом
vector<long long> v1 = ouf.read<vector<long long>>(n);
//Считывает вектор из n чисел, с ограничениями на каждое число от 1 до 100
vector<long long> v2 = ouf.read<vector<long long>>(n,
make_default_reader<long long>(1, 100));
}
На текущий момент поддерживается чтение целых чисел, чисел с плавающей точкой, pair
, vector
, string
.
Метод read<string>
по умолчанию читает token, однако любой объект можно считать альтернативным способом. Для этого нужно первым аргументом передать Reader
.
Если нужно часто считывать какой-то объект с недефолтным reader
, то можно воспользоваться классом Alias
:
typedef Alias<string, LineReader> Line;
//теперь
string nextLine = inf.read<Line>();
//эквивалентно записи
string nextLine = inf.read<string>(LineReader());
//или
LineReader reader;
string nextLine = inf.read<string>(reader);
Библиотеку можно расширять двумя способами
- добавление новой функциональности в библиотеку. Это всегда не так просто, так как библиотека довольно сложная и не многие захотят в ней разбираться. Хотя развитие этой библиотеки на мой субъективный взгляд довольно интересно и познавательно.
- добавление новых пользовательских классов, которые автоматические станут поддерживаться библиотекой без ее изменения. (немного об этом есть в tutorial). Этот способ крайне прост и практически не требует понимания внутреннего устройства библиотеки. Это может быть оформлено как отдельный файл, который может распространяться отдельно, либо быть включен в библиотеку. Разве не хочется в чекере писать просто
inf.read<Point>
и получать сразу точку на плоскости?
Текущую версию в одном файле можно скачать отсюда. Данный файл автосгенерирован, поэтому, если вы хотите посмотреть на устройство проекта или хотите решить не поучавствовать ли в разработке, то лучше смотреть репозиторий. Там же вы найдете чуть более подробную документацию.