Впечатления от знакомства с Ultimate++

    Если вы фрилансер или любите экспериментировать с экзотическими средами под С++, то стоит обратить внимание на экосистему 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 sended\n", 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 listening\n", 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);
      }
      
      image

    SQL


    Просто посмотрите сюда и сюда. Поклонники php/Yii должны оценить.

    QTF (ReportView)


    QTF это собственный формат U++ для расширенного оформления текста. Используется в RichEdit и при генерации отчетов. В TheIDE имеется специальный дизайнер для экспериментов:

    image

    Также предусмотрен специальный диалог для печати отчета (сохранение в 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);
    

    image

    Стилевое оформление текста обрамляется тэгами [ и ], причем сначала за скобкой [ идут 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));
      

      image
    • Если посмотреть примеры реальных приложений, то можно заметить, что там нет скриншотов с иконками и текстом в меню, потому что это сделать нельзя — иконки с текстом могут иметь только вложенные разделы меню, а главное меню всегда текстовое.
    • У кнопок нет свойств по-умолчанию для изменения размера.
    • Не поддерживается удобное блочное смещение строк через Alt+Shift+стелочки+tab, что после Visual Studio и Notepad++ напрягает.
    • Самая большая проблема редактором касается не всегда корректной отмены последней операции. Проявляется в двух ипостасях: при ручной отмене (или Ctrl+Z) соседние и не только строки могут начать перемешиваться (за день один- два раза ловится); при запуска через F5 или Ctrl+F5 отменяется, опять же иногда, последнее редактирование (случается чаще).
    • Есть проблемы с Intellisense, который охотнее отображает доступные сигнатуры уже существующей в коде переменной, чем у только что написанной. Также хотелось бы распознавания ситуаций, когда при вызове процедуры у объекта из списка код obj.f() не трансформировался бы в obj.f() ()

    Резюме


    Вливайтесь! Многие моменты, которые я не выписал, требуют активного улучшения. 32 мб с небольшим дистрибутива этого заслуживают.
    Поделиться публикацией

    Похожие публикации

    Комментарии 12
      0
      Недавно искал либу для чтения и редактирования док(старых и новых) файлов. Прочитал топик, вроде раньше не находил эту, пошел почитал доки:
      OfficeDoc handles the suites through «Ole Automation» so it requires either OpenOffice or Microsoft Office to be previosly installed in the computer.

      Жаль, остается использовать Qt Activex как и раньше.
        0
        Проблема OfficeAutomation в отсутствии прямого доступа к API Excel/Word из-за поддержки кроссплатформенности. Как следствие, функций прослойки часто не хватало, например, взять задачу выравнивания текста по центру в Word'e. Еще столкнулся с проблемой встраивания этих приложений как дочерний фрейм в сплиттере как тут в C#. Так вот скрыть командные панели до сих пор не удалось, так как не смотря на пример выше разработчик ссылается, что эта функция отключена начиная с MS Office 2007. Интересно как в Qt ActiveX с этим. Предположу, что это аналог DSOFormer, который закрыли как проект из-за неких проблем с новыми офисами.
        +4
        Не смог редактировать предыдущий пост, пришлось написать новый.
        Я лишь поверхностно ознакомился с либой, можете вкратце описать основные отличия и если есть преимущества в сравнении с тем же Qt и более легковестным Boost?
          0
          Во-первых, на фоне обоих он выглядит легковесным в плане развертывания, по крайней мере на Windows (Linux не пробовал). Во-вторых это очень краткий код, нацеленный на быстрое прототипирование. Здесь небольшое сравнение с Qt, Java/Swing и wxWidgets. И это действительно так, потому что быстро накидать GUI и проиллюстрировать баг не лень. Последние присутствуют в большем количестве чем Boost/Qt. Документации и форума часто не хватает, если требуется шаг влево, приходится поглядывать в ядро (60 сообщений за месяц все-таки много когда решаешь прикладную задачу, а не развиваешь U++). Комьюнити, судя по ~1200 зарегистированным юзерам на форуме, небольшое и это сдерживает интенсивное развитие. В третьих сильная сторона это работа с SQL в объектном стиле очень компактно и без нареканий. В четвертых это встроенные 2d графики, что делает U++ очень удобной для мат. моделирования вкупе с быстрым накидыванием гуя. Матриц как в UBlas нет, но как либа доступен Eigen.
            0
            С Qt они сравнили хорошо в свою пользу, правда не учли прекраснейшего QtDesigner позволяющего работать в окошками в визуальной среде, а потом удобно пользоваться диалогом из кода.
            У Qt наверное лучшая документация из всего, что я когда-либо встречал, а количество полезных классов и функций просто зашкаливает.

            В плане общего кода, если не нужны окошки — буст явно лучше, так как де-факто уже стандартен, и используется во многих проектах.
              0
              Да, скорее говорить о U++ надо в контексте задач, где он выглядит выигрышно. Для себя я определил два направления: мат моделирование (если требуется реалтайм визуализация расчетных величин, а Matlab/Maple не хочется использовать) и системно-администраторские утилиты (за счет удобного SQL и не больших требованиях к красивостям). Хочу также поделиться красивым примером использования U++: «Силос-мастер».
              +1
              1. Просмотрел сравнение с Qt. Ну что тут сказать, или парни которые писали код не знают что такое QtDesigner, или пример еще с Qt3, когда этого редактора еще не было, писали код, или же намеренно делают все вручную что бы запугать и не дать потенциальному пользователю U++ попробовать QtGui. Больше половины кода, да почти все что связано с элементами интерфейса(кнопки, лейблы, едиты, табы etc) все делается очень легко и быстро с помощью QtDesigner. Останется связать события этих элементов на свою функцию-обработчик + останется код на обработку самой инфы. В общем, это сравнению некорректно.

              2.
              Документации и форума часто не хватает, если требуется шаг влево, приходится поглядывать в ядро (60 сообщений за месяц все-таки много когда решаешь прикладную задачу, а не развиваешь U++)...

              Очень большой минус, Qt имеет замечательную документацию(оффлайн, онлайн), комьюнити десятки тысяч людей, если не разобрался с проблемой на форуме очень быстро напишут решение если оно есть. Про развитие вообще молчу, каждый день под сотню [url=https://codereview.qt-project.org/#q,status:open,n,z]коммитов[/url].

              3.
              В третьих сильная сторона это работа с SQL в объектном стиле очень компактно и без нареканий.

              Ничего сверхестесвтенного, все почти так же как в Qt.

              4.
              В четвертых это встроенные 2d графики.

              А вот это уже реальный плюс U++. В Qt такие вещи в виде сторонних либ. Есть замечательные [url=http://qt.digia.com/Product/Qt-Core-Features--Functions/Charts/]Qt Charts[/url](платная), из бесплатных есть[url=https://sourceforge.net/projects/qwt/]Qwt(LGPL)[/url], разрабатываемый больше 10 лет, у нас в клиентских программах используется. Вот недавно появилась симпатичная [url=http://www.qcustomplot.com/]QCustomPlot(GPL)[/url], жаль нам из-за лицензии не подходит. В общем, я бы как раз и развивал эти графики в U++, так как адекватных вариантов если не использовать Qt я не видел, с учетом если писать на С++.

              Итого для меня U++ пока только «посмотреть — поиграться».

                0
                Чего это я не могу редактировать комменты? :( По привычке bbcodы юзаю.
                  0
                  Как раз сейчас и использую U++ на работе из-за графиков. До этого в своих проектах работал на связке WTL + NTGraph. В этот раз устал от большого количества лишнего кода WTL, regsvr32 для NTGraph выдал ошибку, я на это плюнул и с удовольствием стал работать с Upp::ScatterCtrl. Проблем нет. Qt будет скорее всего незаменим в промышленных задачах, мне же как математику (для GUI, даже ) важно иметь под рукой базовый инструмент для быстрого прототипирования, с чем U++ справляется.
                    0
                    Для быстрого прототипирования c Qt можно использовать Python. Быстрее (прототипировать) уже вроде некуда.
                      0
                      А скорость?
                        +1
                        Во-первых, если вы занимаетесь прототипированием, то вопрос скорости работы программы вас занимать должен в последнюю очередь. Это быстрая реализация системы\алгоритма. Проверили идею, пересмотрели архитектуру, изменили инструменты при необходимости.

                        Во-вторых, если вам нужны матрицы, NumPy осуществляет поддержку многомерных массивов и матриц и имеет библиотеку высокоуровневых математических функций для операций с этими массивами. Ну и относительно скорости работы небольшая цитата из Вики:

                        любой алгоритм, который может быть выражен в основном как последовательность операций над массивами и матрицами, работает так же быстро, как эквивалентный код, выполняемый в MATLAB, а после специальной оптимизации скорость может достигнуть скорости компилируемых языков типа Cи.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое