eao197 on the Web Сайт Евгения Охотникова |
[ Главная | Проекты | Описания | Об авторе | Лицензия ] |
C++ tricks: no_ifdef
Однажды я столкнулся с тем, что функция iconv (библиотека libiconv) на разных платформах имеет разный тип своего второго аргумента. Например, на платформе Windows:
size_t iconv( iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft );
и на ряде unix-подобных систем:
size_t iconv( iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft );
Это означало, что в кросс-платформенном коде нужно было использовать директивы препроцессора #if/#else:
ret = iconv( cd, #ifndef __unix__ ( const char ** ) &icv_in, &icv_inlen, #else ( char ** ) &icv_in, &icv_inlen, #endif &icv_out, &icv_outlen );
Во-первых, такая запись усложняет восприятие исходного текста. Во-вторых, этот код приходится модифицировать при переходе на платформу, на которой используется Unix-вариант iconv, но не определен символ __unix__. Например, такой платформой является Tandem OSS (Open System Services) /он же HP NonStop/.
Можно было бы продолжать перечислять в #if названия платформ, на которых применяется Unix-вариант iconv. Но это тупиковый вариант. Тем более, что C++ позволяет написать код, который сам определит, какой тип параметра нужно использовать:
template< class A, class B, class C, class D, class E > inline B source_ptr( const char ** ptr, size_t (*fn)( A, B, C, D, E ) ) { return (B) ptr; } ... // При обращении к iconv используется шаблонная функция source_ptr: ret = iconv( cd, source_ptr( &icv_in, iconv ), &icv_inlen, &icv_out, &icv_outlen );
Думаю, что аналогичные приемы, основанные на шаблонах, можно применять даже для устранения таких несоответствий между платформами, как различное количество аргументов в функциях.
© 2003-2004 Е.А. Охотников
$LastChangedDate: 2004-10-28 08:44:53 +0400 (Thu, 28 Oct 2004) $