Если вы фрилансер и любите экспериментировать с экзотическими средами под С++, то стоит обратить внимание на экосистему Ultimate++, о которой я узнал совсем недавно благодаря циклу статей Семена Есилевского (ч.1, ч.2, ч.3, ч.4 — все есть на вики) с таким финальным напутствием:
«Перевешивают ли выгоды U++ его необычность и высокий «барьер вхождения»? На мой взгляд, да. U++ – прекрасный выбор для кроссплатформенных проектов, которые разрабатываются «с нуля», особенно если предполагается интенсивное использование баз данных.»
Под катом те нюансы U++, которые удалось раскопать на форуме и в мануалах за месяц ежедневной работы над редактируемым справочником документов, хранящихся в базе. Сразу отмечу, что сравнения с «замечательной троицей» не будет, так как раньше для простейшего gui использовал WTL и с надеждой смотрел на библиотеку eGUI++, которую, к сожалению, автор забросил, а подхватить некому.
Прежде всего, Ultimate++ это ультиматум: либо собственная среда TheIDE, либо, к примеру, такой набор под Windows, как Visual Studio + STL + POCO + WTL. Как следствие, приходится забыть об исключениях, хотя в остальном ядро приличное, что иллюстрируют фрагменты написанного мною кода асинхронной клиент-серверной передачи файлов.
Ядро
- Делегаты (основное средство для привязки событий в GUI; лично меня они зацепили больше всего)
//ограничения: //функция не должна возвращать значений, а также иметь больше 4х входных параметров void Func() {}; void Func4(int, double, String, Value) {} //делегаты для функций GUI_APP_MAIN { Callback cb = callback(Func); cb(); //stateful Callback cb4 = callback4(Func4, 1, 2, AsString(3), 4); cb4(); //stateless Callback4<int double string value> cb1 = callback(Func4); cb1(1, 2, AsString(3), 4); } //делегаты в классе class AppMain { public: //для THISBACK typedef AppMain CLASSNAME; Callback cb; Callback cb4; AppMain() { cb = THISBACK(Func); cb4 = THISBACK4(Func4, 1, 2, AsString(3), 4); } void Func() {}; void Func4(int, double, String, Value) {} }; //делегаты для объектов GUI_APP_MAIN { AppMain m; m.cb = callback(&m, &AppMain::Func); m.cb4 = callback4(&m, &AppMain::Func4, 1, 2, AsString(3), 4); } </int>
- Синглтон
//класс SomeClass должен иметь конструктор по-умолчанию Single<someclass>().SomeMethod();
- Логирование (имейте ввиду, что для вещественных чисел вместо %lf используется %f)
//вывод на экран и в файл StdLogSetup(LOG_COUT|LOG_FILE); ... LOG(Format("Total %d files have sendedn", n)); LOG("Total " << n << " files have sended");
- INI-файлы
VectorMap<string string> config = LoadIniFile(GetExeDirFile("config.ini")); String host = config.Get("HOST"); int port = ScanInt(config.Get("PORT")); for (int i = 0; i < config.GetCount(); i++) { if ("FILE" == config.GetKey(i)) { Cout() << config[i] << "n"; } }
- Многопоточность
//без ожидания завершения Thread::Start(callback(Func)); //c ожиданием завершения Thread th; th.Run(callback(Func)); th.Wait(); Thread::ShutdownThreads();
Насколько я понял, OpenMP не поддерживается, вместо этого предалагается CoWork, работающий с делегатами, что для распараллеливания циклов совсем не удобно.
- Текстовый JSON (бинарные данные поддерживаются за счет пары функций Base64Encode/Base64Decode)
FileIn fp(fname); Json json; json("fname", fname)("fsize", (int)fp.GetSize())("fdata", Base64Encode(LoadFile(fname))); ValueArray jsonAr = ParseJSON(json.ToString()); fname = jsonAr[0]; int fsize = jsonAr[1]; String fdata = Base64Decode(jsonAr[2]);
- Сокеты
TcpSocket server; if (!server.Listen(port)) { LOG(Format("Can't open server port %d for listeningn", port)); return; } for(;;) { LOG("Waiting..."); TcpSocket socket; if (socket.Accept(server)) { String msg = ""; for (int c = socket.Get(); c > 0 && c != 'n'; c = socket.Get()) { msg.Cat(c); } } }
- RegExp (PCRE)
RegExp reg("(\\)"); String path = "D:\test.txt"; if (reg.Match(path)) { int last; int first; reg.GetMatchPos(0, first, last); String drive = path.Mid(0, last); String fname = path.Mid(last); }
- Встроенная проверка утечек памяти (malloc не отслеживается)
GUI_APP_MAIN { double *d = new double(0); }
SQL
Просто посмотрите сюда и сюда. Поклонники php/Yii должны оценить.
QTF (ReportView)
QTF это собственный формат U++ для расширенного оформления текста. Используется в RichEdit и при генерации отчетов. В TheIDE имеется специальный дизайнер для экспериментов:
Также предусмотрен специальный диалог для печати отчета (сохранение в pdf есть в недрах ReportWindow):
Color rgb_color = Color(109, 171, 211);
String qtf_color = Format("@(%d.%d.%d)", rgb_color.GetR(), rgb_color.GetG(), rgb_color.GetB());
String qtf;
qtf.Cat(Format("[R9/%s Habrahabr &]", qtf_color));
qtf.Cat(Format("[_%s лента] [ посты] [_%s q\&a] [_%s события] [_%s хабы] [_%s компании]",
qtf_color, qtf_color, qtf_color, qtf_color, qtf_color));
Report rep;
rep << qtf;
ReportWindow().Perform(rep);
Стилевое оформление текста обрамляется тэгами [ и ], причем сначала за скобкой [ идут QTF-идентификаторы, а затем только через пробел текст. В целом принцип как в HTML, разница лишь в наименованиях.
Bazaar
Bazar это набор пользовательских библиотек для специфических нужд, среди которых мне очень пригодилась кроссплатформенная работа с Word/Excel в Office Automation:
#include <OfficeAutomation/OfficeAutomation.h>
GUI_APP_MAIN
{
//Excel
OfficeSheet sheet;
bool xlsOn = sheet.IsAvailable("Microsoft");
if (xlsOn)
sheet.Init("Microsoft");
//Open Office Calc
if (!xlsOn) {
xlsOn = sheet.IsAvailable("Open");
if (xlsOn)
sheet.Init("Open");
}
if (xlsOn) {
FileSel fs;
fs.Type("Файлы таблиц", "*.xls *.xlsx");
fs.AllFilesType();
if (fs.ExecuteOpen("Выберите Excel файл")) {
sheet.OpenSheet(~fs, true);
sheet.AddSheet(true);
}
}
//Word
OfficeDoc doc;
//Если установлен Word2003 и Word2007, открывается почему-то Word2003. Разработчик разводит руками.
bool docOn = doc.IsAvailable("Microsoft");
if (docOn)
doc.Init("Microsoft");
//Open Office Writer
if (!docOn) {
docOn = doc.IsAvailable("Open");
if (docOn)
doc.Init("Open");
}
if (docOn) {
FileSel fs;
fs.Type("Файлы Word", "*.doc *.docx *.rtf");
fs.AllFilesType();
if (fs.ExecuteOpen("Выберите Word файл")) {
doc.OpenDoc(~fs, true);
doc.AddDoc(true);
}
}
}
Нюансы
- Русскоязычный диалог выбора файлов не переводит вложенные папки, причем даже если сама Windows руссифицирована:
SetLanguage(SetLNGCharset(GetSystemLNG(), CHARSET_UTF8));
- Если посмотреть примеры реальных приложений, то можно заметить, что там нет скриншотов с иконками и текстом в меню, потому что это сделать нельзя — иконки с текстом могут иметь только вложенные разделы меню, а главное меню всегда текстовое.
- У кнопок нет свойств по-умолчанию для изменения размера.
- Не поддерживается удобное блочное смещение строк через Alt+Shift+стелочки+tab, что после Visual Studio и Notepad++ напрягает.
- Самая большая проблема редактором касается не всегда корректной отмены последней операции. Проявляется в двух ипостасях: при ручной отмене (или Ctrl+Z) соседние и не только строки могут начать перемешиваться (за день один- два раза ловится); при запуска через F5 или Ctrl+F5 отменяется, опять же иногда, последнее редактирование (случается чаще).
- Есть проблемы с Intellisense, который охотнее отображает доступные сигнатуры уже существующей в коде переменной, чем у только что написанной. Также хотелось бы распознавания ситуаций, когда при вызове процедуры у объекта из списка код
obj.f()
не трансформировался бы вobj.f() ()
Резюме
Вливайтесь! Многие моменты, которые я не выписал, требуют активного улучшения. 32 мб с небольшим дистрибутива этого заслуживают.
Автор: shtr