Уже не раз поднимался вопрос о получении количества аргументов в __VA_ARGS__ (для случая 0 аргументов) и итеративном переборе каждого элемента в последовательности, например: темы (1)
Возможно, заинтересует следующее решение:
1. макрос VA_SIZE(...) — возвращает количество переданных аргументов в диапазоне от 0 до 10 (лимит может быть легко увеличен):
— VA_SIZE() возвращает 0;
— VA_SIZE(a) возвращает 1;
— VA_SIZE(a,b) возвращает 2;
— и т.д. Реализация:
2. макрос VA_FOR(macro,data,...) вызывает macro(data, x) для каждого элемента последовательности __VA_ARGS__, где x — элемент последовательности:
— VA_FOR(MACRO, Y,) преобразуется в пустую строку (т.е. ни во что)
— VA_FOR(MACRO, Y, a) -> MACRO(Y,a)
— VA_FOR(MACRO, Y, a, b) -> MACRO(Y,a) MACRO(Y,b)
— и т.д. Реализация
/** \def BOOST_VMD_DATA_SIZE(...)
\brief Expands to the number of comma-separated variadic macro data arguments.
... = variadic macro data.
returns = the number of comma-separated variadic macro data
arguments being passed to it.
The value returned can be between 1 and 64.
*/
Ограничение на данную реализацию: от 1 аргумента и выше.
Это нестандартное использование. C99 и C++0x требуют (ХЗ почему) передачи по меньшей мере одного аргумента в такой макрос:
C99 (N1256) — 6.10.3/4:
If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal the number of parameters in the macro definition. Otherwise, there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...).
C++0x (N3290) — 16.3/4:
If the identifier-list in the macro definition does not end with an ellipsis, the number of arguments (including those arguments consisting of no preprocessing tokens) in an invocation of a function-like macro shall equal the number of parameters in the macro definition. Otherwise, there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...).
Re[2]: Снова __VA_ARGS__. Теперь для 0 аргументов.
Здравствуйте, Masterkent, Вы писали:
M>SX:
SX>>- VA_SIZE() возвращает 0;
M>Это нестандартное использование. C99 и C++0x требуют (ХЗ почему) передачи по меньшей мере одного аргумента в такой макрос:
M>C99 (N1256) — 6.10.3/4: M>C++0x (N3290) — 16.3/4:
Тогда, реализацию можно изменить с учетом такого вызова:
— VA_SIZE( () ) возвращает 0;
— VA_SIZE( (a) ) -> 1;
— VA_SIZE( (a,b) ) -> 2;
— и т.д.
Использование:
VA_SIZE( (__VA_ARGS__) ) или по аналогии.
Re[3]: Снова __VA_ARGS__. Теперь для 0 аргументов.
SX>Здравствуйте, Masterkent, Вы писали:
SX>>>- VA_SIZE() возвращает 0;
M>>Это нестандартное использование. C99 и C++0x требуют (ХЗ почему) передачи по меньшей мере одного аргумента в такой макрос:
M>>C99 (N1256) — 6.10.3/4: M>>C++0x (N3290) — 16.3/4:
Или так:
— VA_SIZE(, ) возвращает 0;
— VA_SIZE(, a ) -> 1;
— VA_SIZE(, a,b ) -> 2;
— и т.д.
Использование:
VA_SIZE(, __VA_ARGS__ ) или по аналогии.
Но за описание проблемы, спасибо!
Re[3]: Снова __VA_ARGS__. Теперь для 0 аргументов.
Здравствуйте, SX, Вы писали:
SX>Ограничение на данную реализацию: от 1 аргумента и выше.
Да, да, я видел
Если либа попадёт в буст, то я думаю автор поправит это.
А ваш код я унёс к себе в библиотеку, спасибо.
Конечно с указанием авторства и ссылкой на рсдн.
Re[2]: Снова __VA_ARGS__. Теперь для 0 аргументов.
Masterkent:
M>Это нестандартное использование. C99 и C++0x требуют (ХЗ почему) передачи по меньшей мере одного аргумента в такой макрос:
Впрочем, вероятно, я поторопился с выводами Вроде, нигде не сказано, что аргумент для ... не может состоять из пустой последовательности токенов (для обычных параметров пустая последовательность точно допустима). Если пустая последовательность — тоже корректный аргумент, то VA_SIZE() можно рассматривать как использование макроса с одним аргументом (состоящим из пустой последовательности токенов), и тогда всё законно (правда, VA_SIZE(), получается, означает не количество переданных аргументов, т.к. их не 0, а 1 ).
#define MACRO(x, ...)
MACRO(a, b) // законное использование
MACRO(a,) // законное использование
MACRO(a) // незаконное использование
Здравствуйте, SX, Вы писали:
SX>Буду рад, если кому-нибудь пригодится...
Попробовал использовать. Маленькое пожелание, сделать имена макросов более семантически нагруженными, чтобы избежать коллизий
INVOKE -> SX_VA_INVOKE и т.д.
Re[3]: Снова __VA_ARGS__. Теперь для 0 аргументов.
Здравствуйте, Masterkent, Вы писали:
M>Если пустая последовательность — тоже корректный аргумент, то VA_SIZE() можно рассматривать как использование макроса с одним аргументом (состоящим из пустой последовательности токенов), и тогда всё законно (правда, VA_SIZE(), получается, означает не количество переданных аргументов, т.к. их не 0, а 1 ).
M>
#define MACRO(x, ...)
M>MACRO(a, b) // законное использование
M>MACRO(a,) // законное использование
M>MACRO(a) // незаконное использование
Попытаюсь объяснить свою точку зрения, по которой вызов VA_SIZE() должен возвращать именно 0, а не 1.
Предположим у нас имеются кортежи, оформленные в коде, как:
Отсутствие элементов в кортеже (или пустая последовательность токенов в нём) по здравой логике трактуется как кортеж с 0 аргументами.
Для определения количества элементов в кортеже нужно именно такое поведение VA_SIZE. Пример кода:
Здравствуйте, Владислав Курмаз, Вы писали:
ВК>Попробовал использовать. Маленькое пожелание, сделать имена макросов более семантически нагруженными, чтобы избежать коллизий ВК>INVOKE -> SX_VA_INVOKE и т.д.
По поводу коллизий имен — это, конечно, правильно (особенно для препроцессора). Жаль, что для него нет аналогов пространств имен.
Код приведен, большей частью для описания идеи. А использование префикса SX_ уж очень не скромно, на мой взгляд . Думаю, нет смысла навязывать конкретный префикс пока это просто пара макросов. А так, достаточно и PP_.
Спасибо Вам за интерес к теме.
С уважением, Сергей.
Re[4]: Снова __VA_ARGS__. Теперь для 0 аргументов.
SX>Отсутствие элементов в кортеже (или пустая последовательность токенов в нём) по здравой логике трактуется как кортеж с 0 аргументами.
Твоя реализация VA_SIZE всё же накладывает дополнительные ограничения на первый аргумент макроса. Применение ## должно образовывать valid preprocessing
token, поэтому в качестве первого аргумента такого VA_SIZE, например, нельзя использовать (a) или "a".
Re[5]: Снова __VA_ARGS__. Теперь для 0 аргументов.
Здравствуйте, Masterkent, Вы писали:
M>Твоя реализация VA_SIZE всё же накладывает дополнительные ограничения на первый аргумент макроса. Применение ## должно образовывать valid preprocessing M>token, поэтому в качестве первого аргумента такого VA_SIZE, например, нельзя использовать (a) или "a".
Согласен. Нужно думать как быть в этом случае. Если решение есть, то, думаю, мы обязательно о нем узнаем в будущем...
Предлагается обновленная реализация макроса VA_SIZE().
В ней снимаются ограничения на использование в качестве первого аргумента последовательностей вида "xxx" и (yyy).
Ограничения на текущую реализацию:
Количество аргументов от 0 до 10 (лимит может быть увеличен);
В качестве входной последовательности (списка аргументов) для VA_SIZE не могут выступать данные из одного элемента-макроса.
Т.е. использование VA_SIZE( MACROS ) выдает предупреждение (или ошибку), если MACROS — имя макроса, определенного через #define. (MSVC 2010 выдает корректный результат, но с предупреждением; MinGW GCC 4.5.2 — ошибку на количество параметров в макросе MACROS)
В то же время использование VA_SIZE( MACROS1, MACROS2 ) — корректно.
Здравствуйте, SX, Вы писали:
SX>Здравствуйте, Masterkent, Вы писали:
M>>Твоя реализация VA_SIZE всё же накладывает дополнительные ограничения на первый аргумент макроса. Применение ## должно образовывать valid preprocessing M>>token, поэтому в качестве первого аргумента такого VA_SIZE, например, нельзя использовать (a) или "a".
SX>Согласен. Нужно думать как быть в этом случае. Если решение есть, то, думаю, мы обязательно о нем узнаем в будущем...
Будущее уже наступило offtop: Вчера вечером лег спать около 23:00. Долго не мог уснуть. Приблизительно в 23:45 придумалось РЕШЕНИЕ! Вывод: нужно больше отдыхать...
Для того, чтобы в качестве первого параметра принималась последовательность вида "a", необходимо убрать из реализации VA_SIZE преобразование ##.
Правда, одно ограничение все же есть, а именно:
последовательность символов, подаваемая в качестве аргумента(ов) VA_SIZE, не может содержать один элемент — макрос
MACROS
, где MACROS — имя макроса.
В то же время последовательности, содержащие более одного макроса: