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) $
e-mail



Hosted by uCoz