Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Macros with modifiers

Boost , Chapter 1. The Variadic Macro Data Library 1.9 , Chapter 1. The Variadic Macro Data Library 1.9

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Базовая функциональность для макросов VMD для анализа типов данных была предоставлена с использованием необходимых параметров этих макросов. Эта базовая функциональность может быть вполне адекватной для макропрограммистов, чтобы эффективно использовать VMD в своих усилиях по программированию.

Некоторые из этих макросов принимают необязательные параметры, называемые в целом «модификаторами», которые улучшают или изменяют функциональность этих макросов различными способами. Все модификаторы являются идентификаторами VMD.

Во всех ситуациях модификаторы являются необязательными параметрами, которые анализируются VMD для обеспечения расширенной функциональности некоторых его макросов. Они никогда не требуются как часть базовой функциональности макроса.

Когда модификаторы используются в качестве дополнительных аргументов для макроса, они могут быть введены после требуемых параметров в любом порядке, и VMD все равно будет правильно обрабатывать дополнительные параметры.

Существует два основных типа модификаторов: «специфические модификаторы» и «модификаторы, определяемые пользователем». Конкретные модифферы начинаются с BOOST_VMD_ и являются зарегистрированными и предварительно обнаруженными идентификаторами, известными VMD. Конкретные модификаторы изменяют расширение конкретных макросов различными способами, которые будут впоследствии объяснены. Определяемые пользователем модификаторы - это определяемые пользователем идентификаторы, которые конечный пользователь определенных макросов должен зарегистрировать и предварительно обнаружить для себя. Они также изменяют расширение отдельных макросов различными способами, которые впоследствии будут объяснены.

Для любого конкретного макроса, если конкретный модификатор не подходит, он просто игнорируется. Это означает, что VMD никогда не генерирует ошибку предварительной обработки или дает неправильный результат только потому, что конкретный модификатор не применяется для конкретного макроса. Любой модификатор, который не распознается как конкретный модификатор, рассматривается как определяемый пользователем модификатор. В тех случаях, когда пользовательский модификатор не подходит, он просто игнорируется.

Ситуации, когда модификаторы могут быть использованы для повышения базовой функциональности макросов VMD, можно разделить на конкретные типы конкретных модификаторов. Каждый конкретный тип конкретного модификатора имеет имя, функциональность и набор идентификаторов, связанных с этим конкретным типом. Каждый конкретный тип конкретного модификатора может использоваться в качестве дополнительных параметров в одном или более назначенных макросах в зависимости от конкретного типа модификатора.

Когда в качестве необязательного параметра указывается более одного взаимоисключающего конкретного модификатора из определенного типа модификатора, вступает в силу последний указанный параметр. Это позволяет программисту переопределить конкретный модификатор, добавив переопределенный идентификатор в качестве дополнительного аргумента в конце вызова макроса.

Файлы заголовков для конкретных модификаторов автоматически включаются, когда файлы заголовков для макросов, принимающих эти конкретные модификаторы, включены.

Файлы заголовков для пользовательских модификаторов, которые регистрируют и предварительно обнаруживают эти пользовательские модификаторы, должны быть включены по мере необходимости программистом, использующим эти модификаторы.

Следующие темы будут объяснять каждый конкретный тип модификатора и где он может быть использован.

Ряд макросов способны возвращать тип данных в виде v-типа, а не сами данные. Наиболее очевидным из них является BOOST_VMD_GET_TYPE, который обычно возвращает тип ввода.

Модификаторы типа возврата включаются, выключаются или каким-либо образом изменяют тип возвращаемых данных.

Эти модификаторы:

  • BOOST_VMD_RETURN_NO_TYPE, не возвращайте тип данных.
  • BOOST_VMD_RETURN_TYPE возвращает тип данных, анализирующих любую синтаксическую конструкцию, похожую на трубку, в качестве наиболее специфического типа. Это означает, что любая конструкция, похожая на кортеж, сначала анализируется как возможный список, затем как возможный массив, если это не список, и, наконец, как кортеж, если это не список или массив.
  • BOOST_VMD_RETURN_TYPE_LIST, сначала разберите любую синтаксическую конструкцию в виде возможного списка, а затем в виде кортежа, если это не список.
  • BOOST_VMD_RETURN_TYPE_ARRAY, сначала в качестве возможного массива, а затем в качестве кортежа, если это не массив.
  • BOOST_VMD_RETURN_TYPE_TUPLE, рассматривайте любую синтаксическую конструкцию только как синтаксическую конструкцию.

Когда VMD анализирует вход в целом, он должен определить тип каждого элемента данных входа. Почти для всех типов данных VMD это никогда не является проблемой. Для массива или типов данных списка это может быть проблемой, как объясняется при обсуждении разбора массивов и списков соответственно с использованием конкретных макросов BOOST_VMD_IS_ARRAY и BOOST_VMD_IS_LIST. Проблема в том, что действительный кортеж может быть недействительным списком или недействительным массивом, анализ которого в качестве более конкретного типа приведет к UB. Из-за этого, когда VMD анализирует ввод в целом, и только данные элемента необходимы для правильного анализа, он анализирует все данные, подобные кортежу, как кортеж, а не как список или массив.

Когда VMD анализирует ввод в целом, и тип данных требуется каким-то образом как часть возврата макроса, VMD по умолчанию анализирует наиболее конкретный тип каждого элемента данных, чтобы вернуть наиболее точный тип. В этой ситуации по умолчанию модификатор BOOST_VMD_RETURN_TYPE действует внутри компании без необходимости уточнения.

Если в качестве необязательных параметров указаны более одного модификатора возвратного типа, то действует последний из указанных.

Usage with BOOST_VMD_GET_TYPE

Единственным макросом, в котором VMD без использования модификаторов просят вернуть тип данных, является BOOST_VMD_GET_TYPE. Для этого макроса модификатор BOOST_VMD_RETURN_TYPE действует внутренне, поэтому, если модификаторы возвратного типа не вводятся в качестве дополнительных параметров. BOOST_VMD_GET_TYPE ищет наиболее специфический тип.

Для макроса BOOST_VMD_GET_TYPE необязательный модификатор типа возврата BOOST_VMD_RETURN_NO_TYPE, если он указан, всегда игнорируется, поскольку целью BOOST_VMD_GET_TYPE является исключительно возвращение v-типа.

Давайте посмотрим, как это работает с BOOST_VMD_GET_TYPE, указывая последовательности VMD, которые имеют кортежи, которые могут быть или не быть действительными списками или массивами.

#include <boost/vmd/get_type.hpp>
#define TUPLE_IS_ARRAY (2,(3,4))
#define TUPLE_IS_LIST (anydata,BOOST_PP_NIL)
#define TUPLE_IS_LIST_OR_ARRAY (2,(3,BOOST_PP_NIL))
#define TUPLE_BUT_INVALID_ARRAY (&2,(3,4))
#define TUPLE_BUT_INVALID_LIST (anydata,^BOOST_PP_NIL)
#define SEQUENCE_EMPTY
#define SEQUENCE_MULTI TUPLE_BUT_INVALID_ARRAY TUPLE_BUT_INVALID_LIST
BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY) will return BOOST_VMD_TYPE_ARRAY, the most specific type
BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_ARRAY
BOOST_VMD_GET_TYPE(TUPLE_IS_ARRAY,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST) will return BOOST_VMD_TYPE_LIST, the most specific type
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_LIST
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY) will return BOOST_VMD_TYPE_LIST, the most specific type
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_ARRAY
BOOST_VMD_GET_TYPE(TUPLE_IS_LIST_OR_ARRAY,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_LIST
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY) will give UB
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY,BOOST_VMD_RETURN_TYPE_ARRAY) will give UB
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_ARRAY,BOOST_VMD_RETURN_TYPE_LIST) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST) will give UB
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST,BOOST_VMD_RETURN_TYPE_TUPLE) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST,BOOST_VMD_RETURN_TYPE_ARRAY) will return BOOST_VMD_TYPE_TUPLE
BOOST_VMD_GET_TYPE(TUPLE_BUT_INVALID_LIST,BOOST_VMD_RETURN_TYPE_LIST) will give UB
BOOST_VMD_GET_TYPE(SEQUENCE_EMPTY)
   will always return BOOST_VMD_TYPE_EMPTY even if we add any return type modifiers
BOOST_VMD_GET_TYPE(SEQUENCE_MULTI)
   will always return BOOST_VMD_TYPE_SEQUENCE even if we add any return type modifiers
Usage with sequence converting macros

Последовательность, преобразующая макросы, преобразует последовательность в композитный тип данных Boost PP или в вариадные данные, где данные каждого элемента в последовательности становятся элементом в композиционном типе назначения. Макросы это:

  • BOOST_VMD_TO_ARRAY преобразует последовательность в массив
  • BOOST_VMD_TO_LIST преобразует последовательность в список
  • BOOST_VMD_TO_SEQ преобразует последовательность в seq
  • BOOST_VMD_TO_TUPLE преобразует последовательность в кортеж
  • BOOST_VMD_ENUM преобразует последовательность в вариадные данные

Когда он делает преобразование, используя только необходимый параметр самой последовательности, он преобразует только значение данных каждого элемента последовательности в элементы композитного типа данных Boost PP или вариадных данных. Поскольку ему требуется только значение данных каждого элемента последовательности, он определяет тип каждого элемента последовательности как наиболее общий тип, который он может быть. Это означает, что все данные, похожие на кортежи, анализируются как кортежи, а не как возможные списки или массивы.

Используя модификатор возвратного типа, мы можем преобразовывать из последовательности VMD в композитный тип данных Boost PP или вариадные данные и сохранять тип данных каждого элемента в последовательности как часть преобразования. При этом каждый из преобразованных элементов композитного типа данных становится двухэлементным набором, где первый элемент является типом данных, а второй элемент - самими данными.

Для макросов преобразования последовательности внутренним набором модификатора типа возврата по умолчанию является BOOST_VMD_RETURN_NO_TYPE, что означает, что тип не сохраняется. Указывая другой необязательный модификатор типа возврата, мы говорим о преобразовании, чтобы сохранить тип на выходе преобразования.

Если последовательность пуста, поскольку нет элементов последовательности, любой модификатор возвратного типа, который мы используем, не достигает ничего, кроме хорошего использования.

Сначала мы покажем, как макросы преобразования последовательностей работают с модификатором BOOST_VMD_RETURN_TYPE, который всегда анализирует наиболее конкретный тип.

#include <boost/vmd/enum.hpp>
#include <boost/vmd/to_array.hpp>
#include <boost/vmd/to_list.hpp>
#include <boost/vmd/to_seq.hpp>
#include <boost/vmd/to_tuple.hpp>
#define BOOST_VMD_REGISTER_ANID (ANID)
#define SEQUENCE_EMPTY_1
#define SEQUENCE_SINGLE 35
#define SEQUENCE_SINGLE_ID ANID
#define SEQUENCE_SINGLE_ARRAY (3,(0,1,2))
#define SEQUENCE_SINGLE_LIST (data,(more_data,BOOST_PP_NIL))
#define SEQUENCE_MULTI_1 (0,1) (2)(3)(4)
#define SEQUENCE_MULTI_2 BOOST_VMD_TYPE_SEQ (2,(5,6))
BOOST_VMD_TO_ARRAY(SEQUENCE_EMPTY_1) will return an empty array '(0,())'
BOOST_VMD_TO_ARRAY(SEQUENCE_EMPTY_1,BOOST_VMD_RETURN_TYPE) will return an empty array '(0,())'
BOOST_VMD_TO_LIST(SEQUENCE_SINGLE) will return a one-element list '(35,BOOST_PP_NIL)'
BOOST_VMD_TO_LIST(SEQUENCE_SINGLE,BOOST_VMD_RETURN_TYPE)
   will return a one-element list '((BOOST_VMD_TYPE_NUMBER,35),BOOST_PP_NIL)'
BOOST_VMD_TO_SEQ(SEQUENCE_SINGLE_ID) will return a one-element seq '(ANID)'
BOOST_VMD_TO_SEQ(SEQUENCE_SINGLE_ID,BOOST_VMD_RETURN_TYPE)
   will return a one-element seq '((BOOST_VMD_TYPE_IDENTIFIER,ANID))'
BOOST_VMD_TO_TUPLE(SEQUENCE_SINGLE_ARRAY) will return a single element tuple '((3,(0,1,2)))'
BOOST_VMD_TO_TUPLE(SEQUENCE_SINGLE_ARRAY,BOOST_VMD_RETURN_TYPE)
   will return a single element tuple '((BOOST_VMD_TYPE_ARRAY,(3,(0,1,2))))'
BOOST_VMD_ENUM(SEQUENCE_SINGLE_LIST) will return the single-element '(data,(more_data,BOOST_PP_NIL))'
BOOST_VMD_ENUM(SEQUENCE_SINGLE_LIST,BOOST_VMD_RETURN_TYPE)
   will return the single element '(BOOST_VMD_TYPE_LIST,(data,(more_data,BOOST_PP_NIL)))'
BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_1) will return a multi-element tuple '((0,1),(2)(3)(4))'
BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_1,BOOST_VMD_RETURN_TYPE)
   will return a multi-element tuple '((BOOST_VMD_TYPE_TUPLE,(0,1)),(BOOST_VMD_TYPE_SEQ,(2)(3)(4)))'
BOOST_VMD_ENUM(SEQUENCE_MULTI_2) will return multi-element variadic data 'BOOST_VMD_TYPE_SEQ,(2,(5,6))'
BOOST_VMD_ENUM(SEQUENCE_MULTI_2,BOOST_VMD_RETURN_TYPE)
   will return multi-element variadic data '(BOOST_VMD_TYPE_TYPE,BOOST_VMD_TYPE_SEQ),(BOOST_VMD_TYPE_ARRAY,(2,(5,6)))'

Давайте посмотрим, как мы можем использовать другие модификаторы типа возврата при выполнении конверсий, чтобы избежать UB, если мы хотим, чтобы тип был частью конверсии, но тип может быть действительным набором, будучи недействительным списком или массивом.

#define TUPLE_IS_VALID_ARRAY (2,(3,4))
#define TUPLE_IS_VALID_LIST (anydata,BOOST_PP_NIL)
#define TUPLE_BUT_INVALID_ARRAY_2 (&2,(3,4))
#define TUPLE_BUT_INVALID_LIST_2 (anydata,^BOOST_PP_NIL)
#define SEQUENCE_MULTI_T1 TUPLE_IS_VALID_ARRAY TUPLE_IS_VALID_LIST
#define SEQUENCE_MULTI_T2 TUPLE_BUT_INVALID_ARRAY_2 TUPLE_IS_VALID_LIST
#define SEQUENCE_MULTI_T3 TUPLE_IS_VALID_ARRAY TUPLE_BUT_INVALID_LIST_2
#define SEQUENCE_MULTI_T4 TUPLE_BUT_INVALID_ARRAY_2 TUPLE_BUT_INVALID_LIST_2

Мы представляем ряд применений различных конверсий последовательностей с каждой из наших четырех различных последовательностей и показываем их результаты.

#include <boost/vmd/to_seq.hpp>
BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE)
   will return the seq '((BOOST_VMD_TYPE_ARRAY,(2,(3,4)))) ((BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL)))'
BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE_ARRAY)
   will return the seq '((BOOST_VMD_TYPE_ARRAY,(2,(3,4)))) ((BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL)))'
BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE_LIST)
   will return the seq '((BOOST_VMD_TYPE_TUPLE,(2,(3,4)))) ((BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL)))'
BOOST_VMD_TO_SEQ(SEQUENCE_MULTI_T1,BOOST_VMD_RETURN_TYPE_TUPLE)
   will return the seq '((BOOST_VMD_TYPE_TUPLE,(2,(3,4)))) ((BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL)))'

SEQUENCE_MULTI_T1 является действительным массивом, за которым следует действительный список. Все модификаторы возвратного типа дают свои результаты без каких-либо UB.

#include <boost/vmd/to_tuple.hpp>
BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid array as an array
BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE_ARRAY)
   will produce UB when attempting to parse the invalid array as an array
BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE_LIST)
   will return the tuple '((BOOST_VMD_TYPE_TUPLE,(&2,(3,4))),(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL)))'
BOOST_VMD_TO_TUPLE(SEQUENCE_MULTI_T2,BOOST_VMD_RETURN_TYPE_TUPLE)
   will return the tuple '((BOOST_VMD_TYPE_TUPLE,(&2,(3,4))),(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL)))'

SEQUENCE_MULTI_T2 - недействительный массив, но действительный кортеж, за которым следует действительный список.

При преобразовании последовательности мы получим UB всякий раз, когда используем модификатор типа возврата, который анализирует тип данных недействительного массива в виде массива. Но если мы используем модификаторы возвратного типа Boost_VMD_RETURN_TYPE_LIST или Boost_VMD_RETURN_TYPE_TUPLE Мы никогда не рассматриваем недействительный массив как массив, а вместо этого как кортеж, и поэтому мы успешно возвращаем тип недействительного массива как BOOST_VMD_TYPE_TUPLE.

#include <boost/vmd/to_array.hpp>
BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid list as a list
BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE_LIST)
   will produce UB when attempting to parse the invalid list as a list
BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE_ARRAY)
   will return the array '(2,((BOOST_VMD_TYPE_ARRAY,(2,(3,4))),(BOOST_VMD_TYPE_TUPLE,(anydata,^BOOST_PP_NIL))))'
BOOST_VMD_TO_ARRAY(SEQUENCE_MULTI_T3,BOOST_VMD_RETURN_TYPE_TUPLE)
   will return the array '(2,((BOOST_VMD_TYPE_TUPLE,(2,(3,4))),(BOOST_VMD_TYPE_TUPLE,(anydata,^BOOST_PP_NIL))))'

SEQUENCE_MULTI_T3 - это действительный массив, за которым следует недействительный список, но действительный кортеж.

При преобразовании последовательности мы получим UB каждый раз, когда используем модификатор типа возврата, который анализирует тип данных недействительного списка в виде списка. Но если мы используем модификаторы возвратного типа Boost_VMD_RETURN_TYPE_ARRAY или Boost_VMD_RETURN_TYPE_TUPLE Мы никогда не рассматриваем список недействительных как список, а вместо этого как набор, и поэтому мы успешно возвращаем тип списка недействительных как BOOST_VMD_TYPE_TUPLE.

#include <boost/vmd/to_list.hpp>
BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid array or invalid list
BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE_ARRAY)
   will produce UB when attempting to parse the invalid array
BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE_LIST)
   will produce UB when attempting to parse the invalid list
BOOST_VMD_TO_LIST(SEQUENCE_MULTI_T4,BOOST_VMD_RETURN_TYPE_TUPLE)
   will return the list '((BOOST_VMD_TYPE_TUPLE,(&2,(3,4))),((BOOST_VMD_TYPE_TUPLE,(anydata,^BOOST_PP_NIL)),BOOST_PP_NIL))'

SEQUENCE_MULTI_T4 - недействительный массив, но действительный кортеж, за которым следует недействительный список, но действительный кортеж.

При преобразовании последовательности мы получим UB каждый раз, когда используем модификатор возвратного типа, который анализирует последовательность, а не ищет только действительные кортежи. Поэтому здесь мы должны использовать модификатор возвратного типа BOOST_VMD_RETURN_TYPE_TUPLE для преобразования последовательности без создания UB.

Usage with BOOST_VMD_ELEM

Функциональность по умолчанию BOOST_VMD_ELEM при использовании требуемых параметров заключается в возврате данных конкретного элемента. Когда BOOST_VMD_ELEM делает это, он анализирует все элементы последовательности, определяя наиболее общий тип данных для каждого элемента. Алгоритм разбора останавливается, когда он достигает номера элемента, данные которого возвращаются. Это означает, что все данные, похожие на кортежи, анализируются как кортежи, а не как возможные списки или массивы.

Используя модификаторы типа возврата в качестве дополнительных параметров, мы можем сказать BOOST_VMD_ELEM вернуть тип найденного элемента, а также его данные в виде двухэлементного кортежа. Первый элемент кортежа — тип данных, а второй элемент кортежа — сами данные.

Когда мы используем модификатор типа возврата с BOOST_VMD_ELEM, который говорит нам вернуть тип данных вместе с данными, конкретный модификатор сообщает только BOOST_VMD_ELEM, как анализировать тип данных для найденного элемента. BOOST_VMD_ELEM будет продолжать анализировать элементы в последовательности, предшествующей найденному элементу, определяя наиболее общий тип данных, поскольку это самый безопасный способ анализа самих данных.

Использование модификатора возвратного типа BOOST_VMD_RETURN_TYPE с BOOST_VMD_ELEM совершенно безопасно, если найденный конкретный элемент не является недействительным списком или массивом, а действительным кортежем. Именно тогда, когда найденный элемент может быть недействительным списком или недействительным массивом, мы должны использовать другие модификаторы типа возврата, чтобы правильно проанализировать тип элемента.

#include <boost/vmd/elem.hpp>
#define BOOST_VMD_REGISTER_ANID_E (ANID_E)
#define SEQUENCE_SINGLE_E 35
#define SEQUENCE_SINGLE_E2 ANID_E
#define SEQUENCE_MULTI_E (0,1) (2)(3)(4)
#define SEQUENCE_MULTI_E_2 BOOST_VMD_TYPE_SEQ (2,(5,6))
BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E) will return '35'
BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_NUMBER,35)'
BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E2) will return 'ANID_E'
BOOST_VMD_ELEM(0,SEQUENCE_SINGLE_E2,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_IDENTIFIER,ANID_E)'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E) will return '(2)(3)(4)'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_SEQ,(2)(3)(4))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E_2) will return 'BOOST_VMD_TYPE_SEQ'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E_2,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_TYPE,BOOST_VMD_TYPE_SEQ)'

Когда мы используем другие модификаторы типа возврата с BOOST_VMD_ELEM, мы делаем это, потому что элемент, который мы хотим, может быть недействительным списком или недействительным массивом, но действительным кортежем, и все же мы все еще хотим, чтобы его тип возвращался как часть результата.

Давайте посмотрим, как это работает с BOOST_VMD_ELEM, указывая последовательности VMD, которые имеют кортежи в виде массивов или списков, которые не могут быть разобраны VMD как таковые без создания UB.

#define TUPLE_IS_VALID_ARRAY_E (2,(3,4))
#define TUPLE_IS_VALID_LIST_E (anydata,BOOST_PP_NIL)
#define TUPLE_BUT_INVALID_ARRAY_E (&2,(3,4))
#define TUPLE_BUT_INVALID_LIST_E (anydata,^BOOST_PP_NIL)
#define SEQUENCE_MULTI_E1 TUPLE_IS_VALID_ARRAY_E TUPLE_IS_VALID_LIST_E
#define SEQUENCE_MULTI_E2 TUPLE_BUT_INVALID_ARRAY_E TUPLE_IS_VALID_LIST_E
#define SEQUENCE_MULTI_E3 TUPLE_IS_VALID_ARRAY_E TUPLE_BUT_INVALID_LIST_E
#define SEQUENCE_MULTI_E4 TUPLE_BUT_INVALID_ARRAY_E TUPLE_BUT_INVALID_LIST_E

Мы представляем несколько вариантов использования BOOST_VMD_ELEM с каждой из четырех последовательностей и показываем их результаты.

#include <boost/vmd/elem.hpp>
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E1,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'

SEQUENCE_MULTI_E1 - это действительный массив, за которым следует действительный список. Все модификаторы возвратного типа дают свои результаты без каких-либо UB.

#include <boost/vmd/elem.hpp>
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid array as an array
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_ARRAY)
   will produce UB when attempting to parse the invalid array as an array
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(&2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(&2,(3,4)))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_LIST,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E2,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'

SEQUENCE_MULTI_E2 - недействительный массив, но действительный кортеж, за которым следует действительный список.

Когда мы получим доступ к элементу 0 нашей последовательности и используем модификатор возвратного типа, который анализирует тип данных в виде массива, мы получим UB. Но если мы используем модификаторы возвратного типа Boost_VMD_RETURN_TYPE_LIST или Boost_VMD_RETURN_TYPE_TUPLE Мы никогда не рассматриваем недействительный массив как массив, а вместо этого как кортеж, и поэтому мы успешно возвращаем тип недействительного массива как BOOST_VMD_TYPE_TUPLE.

Когда мы получим доступ к элементу 1 нашей последовательности, который является как действительным списком, так и действительным набором, мы никогда не получим UB. Мы получим тип возврата элемента, на основе которого мы используем модификатор возврата.

#include <boost/vmd/elem.hpp>
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_ARRAY,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid list as a list
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_LIST)
   will produce UB when attempting to parse the invalid list as a list
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E3,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'

SEQUENCE_MULTI_E3 - это действительный массив, за которым следует недействительный список, но действительный кортеж.

Когда мы получим доступ к элементу 0 нашей последовательности, который одновременно является действительным массивом и действительным кортежем, мы никогда не получим UB. Мы получим тип возврата элемента, на основе которого мы используем модификатор возврата.

Когда мы получим доступ к элементу 1 нашей последовательности и используем модификатор типа возврата, который анализирует тип данных в виде списка, мы получим UB. Но если мы используем модификаторы возвратного типа Boost_VMD_RETURN_TYPE_ARRAY или Boost_VMD_RETURN_TYPE_TUPLE Мы никогда не рассматриваем список недействительных как список, а вместо этого как набор, и поэтому мы успешно возвращаем тип списка недействительных как BOOST_VMD_TYPE_TUPLE.

#include <boost/vmd/elem.hpp>
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid array
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_ARRAY)
   will produce UB when attempting to parse the invalid array
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_LIST) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))'
BOOST_VMD_ELEM(0,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(2,(3,4)))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE)
   will produce UB when attempting to parse the invalid list
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_ARRAY) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_LIST)
   will produce UB when attempting to parse the invalid list
BOOST_VMD_ELEM(1,SEQUENCE_MULTI_E4,BOOST_VMD_RETURN_TYPE_TUPLE) will return '(BOOST_VMD_TYPE_TUPLE,(anydata,BOOST_PP_NIL))'

SEQUENCE_MULTI_E4 - недействительный массив, но действительный кортеж, за которым следует недействительный список, но действительный кортеж.

Когда мы получаем доступ к элементу 0 нашей последовательности, который является недействительным массивом, но действительным кортежем, мы должны использовать модификатор возвратного типа, который не анализирует элемент 0 как массив, иначе мы получим UB. Это означает, что мы должны использовать модификаторы возвратного типа. Boost_VMD_RETURN_TYPE_LIST или Boost_VMD_RETURN_TYPE_TUPLE Поэтому мы никогда не рассматриваем недействительный массив как массив, а вместо этого как кортеж, и поэтому мы успешно возвращаем тип недействительного массива как BOOST_VMD_TYPE_TUPLE.

Когда мы получаем доступ к элементу 1 нашей последовательности, который является недействительным списком, но действительным кортежем, мы должны использовать модификатор возвратного типа, который не анализирует элемент 1 как список, иначе мы получим UB. Это означает, что мы должны использовать модификаторы возвратного типа. Boost_VMD_RETURN_TYPE_ARRAY или Boost_VMD_RETURN_TYPE_TUPLE Поэтому мы никогда не рассматриваем список недействительных как список, а вместо этого как набор, и поэтому мы успешно возвращаем тип списка недействительных как BOOST_VMD_TYPE_TUPLE.

Usage with other modifiers of BOOST_VMD_ELEM

Мы еще не обсуждали остальные модификаторы, которые могут использоваться с BOOST_VMD_ELEM, но модификаторы возвратного типа полностью независимы от любого из них. Это означает, что они могут быть объединены с другими модификаторами, и всякий раз, когда элемент последовательности возвращается, модификаторы типа возврата определяют, что представляет собой значение этого элемента; будь то просто данные элемента или элемент в виде набора типа / данных с типом, парсируемым в соответствии с нашим модификатором типа возврата. Когда мы впоследствии обсуждаем использование других модификаторов с BOOST_VMD_ELEM и ссылаемся на возвращаемый элемент, мы имеем в виду этот элемент, поскольку он определяется модификатором типа возврата, который по умолчанию возвращает только данные элемента.


PrevUpHomeNext

Статья Macros with modifiers раздела Chapter 1. The Variadic Macro Data Library 1.9 Chapter 1. The Variadic Macro Data Library 1.9 может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 1. The Variadic Macro Data Library 1.9 ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 18:38:46/0.011384010314941/0