На вводной странице Boost.Preprocessor приведен пример в A.4.1.1 Горизонтальное повторение
#define TINY_print(z, n, data) data
#define TINY_size(z, n, unused) \
template <BOOST_PP_ENUM_PARAMS(n, class T)> \
struct tiny_size< \
BOOST_PP_ENUM_PARAMS(n,T) \
BOOST_PP_COMMA_IF(n) \
BOOST_PP_ENUM( \
BOOST_PP_SUB(TINY_MAX_SIZE,n), TINY_print, none) \
> \
: mpl::int_<n> {};
BOOST_PP_REPEAT(TINY_MAX_SIZE, TINY_size, ~) // Oh! a tilde!
#undef TINY_size
#undef TINY_print
Ниже приводится объяснение:
Процесс генерации кода запускается вызовом BOOST_PP_REPEAT
макроса высшего порядка , который повторно вызывает макрос, названный его вторым аргументом (TINY_size
). Первый аргумент указывает количество повторных вызовов, а третий может быть любыми данными; он передается без изменений вызываемому макросу. В этом случае TINY_size
не использует эти данные, поэтому выбор для передачи ~
был произвольным. [5]
(акцент мой)
И есть примечание:
[5]
~
- не совсем произвольный выбор. И @
, и $
могли бы быть хорошим выбором, за исключением того, что они технически не являются частью базового набора символов, который должны поддерживать реализации C ++. Идентификатор, такой как игнорируемый, может подвергаться расширению макросов, что приводит к неожиданным результатам.
Тильда, следовательно, просто заполнитель, потому что аргумент необходим, но не нужен. Поскольку любой пользовательский идентификатор подражателя может быть расширен, вам нужно использовать что-то еще.
Оказывается, что ~
в значительной степени не используется (например, двоичное отрицание не так часто называют) по сравнению с +
или -
, поэтому существует небольшая вероятность путаницы. Как только вы остановитесь на этом, его постоянное использование придает тильде значение new ; например, использование operator<<
и operator>>
для потоковой передачи данных стало идиомой C ++.