Напишу-ка я сегодня про еще одну 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 расшифровывать).