четверг, 25 октября 2012 г.

MySQL C Connector + MinGW

Недавно столкнулся с сабжем и довольно сразу нашел решение - http://sourceforge.net/projects/windiana.u/files/mysql/port-mingw/ . Собирать, правда, лучше под MSYS. Но коннектор для C собирается легко и влет. Для C++ - думаю после плясок с бубном тоже возможно.
Родной, от Oracle, естественно не собирается вообще. А жаль.

пятница, 19 октября 2012 г.

Замыкания для бедных

Сегодня речь зайдет о довольно специфичной проблеме, а именно о замыканиях. На текущий момент замыкания включены в новый стандарт C++11, и, собственно, данная проблема, как проблема, исчерпана. Для чего можно применить замыкания? Да для кучи разных задач. В данной конкретной задаче, замыкание было необходимо для реализации произвольного сообщения, которое посылалось одним потоком другому и выполняло в целевом потоке произвольный код.
 На данный момент не все компиляторы на текущий момент хорошо поддерживают старые компиляторы. В данном случае необходимо было реализовать замыкания в довольно старой версии MSVC (2008) и MinGW с версией GCC 4.4.3.  В них был необходим  другой способ для  работы с замыканиями, который бы упростил их создание и объявление до следующих этапов: 
  • Объявление переменных, сохраняемых в контексте функции. Сохраняться будут значения а не ссылки. Для сохранения ссылок стоит использовать smartpointers
  • Объявление исполняемого кода замыкания
  • Инициализация контекста функции внешними переменными
  • Передача функции, как объекта во внешнюю функцию (к примеру, какую-нибудь функцию run)
Также довольно серьезным ограничением является то, что замыкание в данном случае не будет ничего возвращать (для возврата, в принципе, достаточно небольшой модификации решения.).
Довольно простым решением для данной задачи выглядит объявление анонимного класса, который содержит в себе необходимый контекст и метод для исполнения, при этом у данного класса создается объект, который инициализируется и передается во внешнюю функцию. У данного метода есть несколько легкорешаемых проблем:
  • Нельзя объявить несколько переменных внутри одной функции (решается взятием объявления и инициализации в блок)
  • Необходимо скопировать объект внутрь функции передачи (решается путем объявления функции копирования или созданием объекта на куче и другими способами, однако для этого у класса должно быть имя. Однако коррелирующие имена внутри блока кода в данных компиляторах не являются проблемой)
  • Громоздкий синтаксис. Можно решить при помощи макросов.
Дополнительной проблемой в GCC 4.4.3. станет ещё и сигнатура функции run. В обычном случае достаточно шаблонной функции. Однако в нашем случае, инстанцирование не сработает с анонимным классом. Поэтому приходится использовать динамический полиморфизм. Итоговое решение выглядит cледующим образом:


#include <stdio.h>

/** Базовый класс, который будет использован для создания на 
    его основе функций замыкания
 */
class ClosureBasic
{
 public:
    /** Метод класса, который будет описывать замыкания
     */
    virtual void run()=0;
    virtual ~ClosureBasic() {}
};
/** Макрос, с которого должно начинаться определение замыкания
 */
#define CLOSURE {                                \
                 class ____: public ClosureBasic \
                 {                               \
                  public:                        \
                   ClosureBasic  * ___()         \
                   {                             \
                    return new ____(*this);      \
                   }
/** Макрос для объявления переменных контекста. 
    Может быть опущен, однако удобен для сохранения общего стиля
  */
#define CLOSURE_DATA(X) X
/** Макрос для объявления кода замыкания (как общего метода)
 */
#define CLOSURE_CODE(X) virtual void run()  { X }
/** Макрос для инициализации замыкания общим контекстом. 
    Просто конструирует объект по умолчанию и выполняет
    код в нем.
 */
#define INITCLOSURE(X)          } ______; X;
/** Завершающий макрос для передачи замыкания на исполнение
    Может быть опущен, а вызов ______.___() 
    использован для передачи замыкания куда-либо
    Главное - закрывающая фигурная скобка обязательна
 */
#define SUBMITCLOSURE   run(______.___() ); } 
/** Макрос для установки значения переменной внутри замыкания
 */
#define CLSET(PROP,VAL) ______. PROP = VAL;


/** Тестовая функция, которая просто выполняет код
    замыкания
    \param[in] cl сам объект замыкания
 */
void run(ClosureBasic * cl)
{
    cl->run();
    // Данная строка удаляет объект и удалив её, 
    // мы получим утечку памяти
    delete cl;  
}

int main(int argc, char** argv)
{
 int a=55;
 // Простой пример замыкания, которое берет
 // переменную а и выводит её
 CLOSURE
 CLOSURE_DATA( int a;  )
 CLOSURE_CODE( printf("%d\n", a); 
               printf("%d\n", a); 
             )
 INITCLOSURE( CLSET(a,a); )
 SUBMITCLOSURE;
 
 
 return 0;
}