Триксы

Aug 06, 2007 18:44

Напишу-ка я сегодня про еще одну neat штуку, правда на этот раз не подсмотреную и от-refine-ную, а полностью собственного изготовления.

Вступление: в наших юниксах есть такая конвенция: функции возвращают int:
  • -1 - ошибка + ее код кладется в errno
  •  0 - все нормально, если есть какое-то сложное возвращаемое значение - оно в out-параметре.

    Собсна задача: сделать так чтобы при ошибке кидался exception с содержимым errno и его расшифровкой и аргументами функции как ее позвали, но при этом не писать руками кучу одинакового кода врапперов.



    Сам класс exception который бросается устроен способом похожим на описаный в прошлом посте по теме.

    т.е. для нашей задачи оно бросается примерно вот так:

    throw api_call_error_ex(errno, "some_function(формат аргументов)", сами аргументы);

    самая изюминка - это как такие враперы писать, влом ведь руками, а хочется чтобы красиво было (для интересующихся, да да, у меня страсть к форме, она не менее важна чем содержание).
    соответственно делаем макрос (фу-фу!), который зовется примерно так (в зависимости от наличия и количества параметров):

    DEFINE_LIBC_WRAPPER(return_type, function_name); // нету аргументов

    // есть аргументы
    DEFINE_LIBC_WRAPPER(return_type, function_name, ((arg1_type, arg1_format_string))
    ((arg2_type, arg2_format_string))
    [типа и так далее, сколько угодно аргументов]
    );

    такой враппер генерит примерно такую функцию

    return_type function_name_ex(arg1_type arg1 [и т.д.])
    {
    return_type r = function_name(arg1 [и т.д.]);
    if (-1 == r)
    throw api_call_error_ex(errno, "function_name(arg1_format [и т.д.])", arg1 [и т.д.]);
    return r;
    }

    т.е. например для open (их два варианта, пишем для того который короткий).

    DEFINE_LIBC_WRAPPER(int, open, ((char const*, "'%s'")) ((int, "0x%08x")));

    получаем:

    int open_ex(char const *arg1, int arg2)
    {
    int r = open(arg1, arg2);
    if (-1 == r)
    throw api_call_error(errno, "open('%s', 0x%08x)", arg1, arg2);
    return r;
    }

    и потом используем :)
    вообще сами вызовы макросов можно просто нагенерить для всех libc функций которые понадобятся :)

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

    реализация api_call_error оставляется в качестве упражнения читателю, хотя тоже могу выложить для желающих (правда там она слегка сложнее, ибо надо не только канонические errno расшифровывать).

  • work, weird, cpp, trick, fun

    Previous post Next post
    Up