понедельник, 23 мая 2011 г.

Partial template specialization for pointers to __stdcall functions

Если мы хотим написать частичную специализацию шаблона, например, для указателя на функцию, то обычно пишем что-то вроде следующего кода:
template<typename F> class TFunction;

template<typename R, typename T0>
class TFunction<R(*)(T0)>
{
};
Здесь мы пытаемся специализировать шаблон TFunction для указателя на функцию одного аргумента. Далее имеем два указателя:
typedef bool (*my_function_f)(int);             // (1)
typedef bool (__stdcall *my_function_f2)(int);  // (2)
Для (1) специализация, которая написана выше вполне подходит, а вот для (2) — нет. По умолчанию, предполагается что функция использует соглашение вызова __cdecl. Если мы хотим передавать указатели на функции с соглашением вызова __stdcall, то необходимо для этого случая написать отдельную специализацию:
template<typename R, typename T0>
class TFunction<R(__stdcall *)(T0)>
{
};
Кажется, этого достаточно. Однако, при компиляции кода под x64 процессоры ключевое слово __stdcall, которое обозначает порядок вызова функций, игнорируется. Обычно это незаметно, но если вы пытаетесь написать частичную специализацию шаблона, то проявляются неприятные эффекты. А именно, две специализации, которые написаны выше, получаются абсолютно одинаковыми, что приводит к ошибке компиляции. Решением будет отключить компиляцию второй специализации, например, так:
#ifndef _M_X64
template<typename R, typename T0>
class TFunction<R(__stdcall *)(T0)>
{
};
#endif
Макрос _M_X64 предопределен для x64 процессоров.

Ссылки по теме:
  1. What is __stdcall?
  2. Partial template specialization
  3. Calling convention
  4. Predefined Macros

среда, 18 мая 2011 г.

Пап, что ты делаешь на работе

Как объяснить маленькому ребенку (4-5 лет), что папа/мама на работе разрабатывают софт? У меня возникла только одна аналогия для этого возраста — папа пишет книжки на специальном волшебном языке для компьютеров... Ну да, компы их читают и делают то, что там написано. Волшебный язык, конечно, знают не все люди... Книжки бывают разные: в играх много картинок, а есть скучные книжки-программы — совсем без картинок. Кстати, при загрузке Ubuntu пишется сначала куча текста, а потом уже появляется красивый интерфейс (ага, комп дочитал до нужного места, в книжках тоже не сразу понятно где находятся герои), что подтверждает аллегорию.

Понятно, что мой вариант не окончательное описание для википедии, в реальной жизни он эволюционирует с возрастом и по мере накопления опыта — от примитивного до более сложного. Не потому, что дети идиоты, а потому что им не интересны до какого-то возраста сложные объяснения, на каждом этапе свой уровень абстракции.

А у вас возникала необходимость объяснить чем вы занимаетесь?

пятница, 13 мая 2011 г.

sum of pairs

Вы когда нибудь пробовали получить сумму элементов контейнера, который хранит элементы типа std::pair? Если да, то вы заметили, что std::pair не определяет operator+. На помощь приходит новый стандарт, в котором пишем лямбда-функцию, или библиотека boost::lambda с которой получаем следующий прекрасный но сложноперевариваемый код:
#include <deque>

#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>

template<typename T>
void summarize()
{
    typedef std::pair<T, T> pt_t;
    std::deque<pt_t> xs;
    using namespace boost::lambda;

    // fill xs with stuff

    pt_t res = std::accumulate(
        xs.begin(), xs.end(), std::make_pair(T(),T()),
        bind( constructor<pt_t>(),
             bind( std::plus<T>(), bind(&pt_t::first,_1), bind(&pt_t::first,_2) ),
             bind( std::plus<T>(), bind(&pt_t::second,_1), bind(&pt_t::second,_2) )
             )
         );

}