В предыдущих разделах этой документации объяснялось, как VMD может использоваться для анализа типов данных VMD, а также для распознавания пустоты.
Другая область функциональности VMD включает в себя полезные вариадные макросы, основанные на предыдущей функциональности, которая расширяется на аналогичных макросах уже в Boost PP. Эти вариадные макросы можно разделить на разделы, иллюстрирующие эти области поведения:
Подразделы для каждого из них теперь следуют в документации.
Макросы VMD для идентификации типов данных работают лучше всего, когда макрологика может принимать различные пути в зависимости от типа данных, передаваемых для макропараметра. Но иногда метапрограммист препроцессора хочет просто проверить, что данные макропараметров имеют правильный тип данных, в противном случае должна быть сгенерирована ошибка предварительной обработки, чтобы уведомить программиста, ссылающегося на макрос, что переданные данные являются неправильным типом.
Библиотека Boost PP имеет макрос, который производит ошибку предварительной обработки, когда условие, переданное ему, равно 0. Этот макрос называется BOOST_PP_ASSERT. Макрос производит ошибку препроцессора, заставляя вызов на внутренний макрос с неправильным количеством аргументов. В соответствии со стандартом C++ это всегда должно вызывать немедленную ошибку предварительной обработки для соответствующих компиляторов.
К сожалению, VC++ выдаст предупреждение только тогда, когда макросу будет передано неправильное количество аргументов. Поэтому макрос BOOST_PP_ASSERT не создает ошибки предварительной обработки с использованием VC++. Удивительно, но не существует другого способа, которым VC++ Вы можете быть вынуждены выпустить ошибку предварительной обработки, ссылаясь на макрос (если вы найдете один, пожалуйста, расскажите мне об этом). Однако можно создать недействительный C++ в качестве вывода из макровызова, который заставляет VC++ создавать ошибку компилятора, когда VC++ Позже компилятор сталкивается с конструкцией.
Это то, что делает макрос BOOST_VMD_ASSERT. Он использует тот же условный аргумент, что и BOOST_PP_ASSERT, и называет BOOST_PP_ASSERT, когда не используется с VC++, в противном случае, если условие 0, он генерирует ошибку компилятора, генерируя недействительный C++ при использовании с VC++. Ошибка компилятора генерируется путем создания недействительного C++, форма которого:
typedef char BOOST_VMD_ASSERT_ERROR[-1];
Передавая второй дополнительный аргумент, форма которого является идентификатором предварительной обработки, в BOOST_VMD_ ASSERT может генерировать недействительный C++ для VC++, если первый аргумент равен 0, формы:
typedef char optional_argument[-1];
Вместо этого. Это может дать немного больше ясности, если это необходимо, для ошибки C++.
Если первый условный аргумент не равен 0, то BOOST_VMD_ASSERT не производит никакого вывода.
Использование BOOST_VMD_ Макро ASSERT включает в себя общий заголовок:
#include <boost/vmd/vmd.hpp>
или включить конкретный заголовок:
#include <boost/vmd/assert.hpp>
Типы данных имеют свои собственные макросы утверждений. В основном это просто ярлыки для передачи результата идентифицирующих макросов в BOOST_VMD_ASSERT. Эти макросы утверждения являются:
- BOOST_VMD_ASSERT_IS_EMPTY
- идентификатор, BOOST_VMD_ASSERT_IS_IDENTIFIER
- Источник: Boost_VMD_ASSERT_IS_NUMBER
- Исполнитель: Boost_VMD_ASSERT_IS_ARRAY
- Источник: Boost_VMD_ASSERT_IS_LIST
- BOOST_VMD_ASSERT_IS_SEQ
- кортеж, BOOST_VMD_ASSERT_IS_TUPLE
- тип, BOOST_VMD_ASSERT_IS_TYPE
Каждый из этих макросов принимает в качестве параметров тот же аргумент, что и соответствующие им идентифицирующие макросы. Но вместо возврата ненулевого или 0 каждый из этих макросов производит ошибку компилятора, если тип ввода неверен.
Каждый из этих макросов проверяет свое утверждение только тогда, когда макрос BOOST_VMD_ASSERT_DATA устанавливается в 1. По умолчанию BOOST_VMD_ASSERT_DATA устанавливается только на 1 в режиме отладки компилятора. Программист может вручную установить BOOST_VMD_ASSERT_DATA до 1 перед использованием одного из типов данных.
Для использования индивидуальных макросов BOOST_VMD_ASSERT_... используется общий заголовок:
#include <boost/vmd/vmd.hpp>
или включить конкретный заголовок:
#include <boost/vmd/assert_is_empty.hpp>
#include <boost/vmd/assert_is_identifier.hpp>
#include <boost/vmd/assert_is_number.hpp>
#include <boost/vmd/assert_is_array.hpp>
#include <boost/vmd/assert_is_list.hpp>
#include <boost/vmd/assert_is_seq.hpp>
#include <boost/vmd/assert_is_tuple.hpp>
#include <boost/vmd/assert_is_type.hpp>
Компилятор VC++ имеет причуду при работе с BOOST_VMD_ASSERT и макросами утверждения типа данных. Если вы вызываете один из макросов утверждения в другом макросе, который обычно генерирует выходные токены препроцессора, необходимо при использовании VC++ связать результат макроса утверждения с любыми другими данными препроцессора, даже если макрос утверждения не генерирует ошибку.
В качестве простого примера предположим, что у нас есть макрос, ожидающий кортеж и генерирующий 1, если кортеж имеет более 2 элементов, в противном случае он генерирует Обычно мы можем написать:
#include <boost/preprocessor/comparison/greater.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/vmd/assert_is_tuple.hpp>
#define AMACRO(atuple) \
BOOST_VMD_ASSERT_IS_TUPLE(atuple) \
BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(atuple), 2),1,0)
Но для VC++ Мы должны писать
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/comparison/greater.hpp>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/vmd/assert_is_tuple.hpp>
#define AMACRO(atuple) \
BOOST_PP_CAT \
( \
BOOST_VMD_ASSERT_IS_TUPLE(atuple), \
BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_TUPLE_SIZE(atuple), 2),1,0) \
)
VC++ не работает корректно в первую очередь, ошибочно путаясь в выводах компилятора. Но при использовании BOOST_PP_CAT во втором состоянии VC++ будет корректно работать с утверждениями VMD.