Скажем, у нас есть такой макрос
#define FOO(type,name) type name
Что мы могли бы использовать как
FOO(int, int_var);
Но не всегда так просто:
FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2
Конечно, мы могли:
typedef std::map<int, int> map_int_int_t;
FOO(map_int_int_t, map_var); // OK
что не очень эргономично. Необходимо устранить несовместимость типа Plus. Есть идеи, как решить эту проблему с помощью макроса?
c++
c
macros
c-preprocessor
PoP
источник
источник
Ответы:
Поскольку угловые скобки могут также представлять (или происходят в) операторы сравнения
<
,>
,<=
и>=
, макро расширение не может игнорировать запятые внутри угловые скобки , как это происходит в круглых скобках. (Это также проблема для квадратных и фигурных скобок, хотя они обычно встречаются как сбалансированные пары.) Вы можете заключить аргумент макроса в круглые скобки:Проблема в том, что параметр остается заключенным в круглые скобки внутри раскрытия макроса, что предотвращает его чтение как тип в большинстве контекстов.
Хороший прием для обхода этой проблемы состоит в том, что в C ++ вы можете извлечь имя типа из имени типа в скобках, используя тип функции:
Поскольку при формировании типов функций лишние скобки игнорируются, вы можете использовать этот макрос со скобками или без них, если имя типа не включает запятую:
В C, конечно, в этом нет необходимости, потому что имена типов не могут содержать запятых вне скобок. Итак, для кросс-языкового макроса вы можете написать:
источник
template<class KeyType, class ValueType> void SomeFunc(FOO(std::map<KeyType, ValueType>) element) {}
если я применим это решение здесь, структуры, стоящие за макросом, станут зависимыми типами, и теперь для типа требуется префикс typename. Вы можете добавить его, но определение типа было нарушено, поэтому теперь вам нужно вручную перечислить аргументы типа для вызова функции. В итоге я использовал метод Храма для определения макроса для запятой. Это могло выглядеть не так красиво, но работало отлично.[]
а{}
это не так, это только()
печально. См .: Тем не менее, квадратные скобки или фигурные скобки для баланса не#define PROTECT(...) argument_type<void(__VA_ARGS__)>::type
. Передача аргументов теперь легко возможна даже через несколько макросов, а для простых типов вы можете опустить PROTECT. Однако типы функций становятся указателями на функции при такой оценкеЕсли вы не можете использовать круглые скобки и вам не нравится решение Mike SINGLE_ARG, просто определите ЗАПЯТУЮ:
Это также помогает, если вы хотите структурировать некоторые аргументы макроса, как в
который печатает
std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"
.источник
#define STRVX(...) STRV(__VA_ARGS__)
и#define STRV(...) # __VA_ARGS__
, тоstd::cout << STRV(type<A COMMA B>) << std::endl;
распечатаетtype<A COMMA B>
иstd::cout << STRVX(type<A COMMA B>) << std::endl;
распечатаетtype<A , B>
. (STRV
означает «вариативное строковое преобразование» иSTRVX
означает «расширенное вариативное строковое преобразование».)COMMA
. Вот что у меня получилось.Если ваш препроцессор поддерживает вариативные макросы:
В противном случае это немного утомительнее:
источник
Просто определите
FOO
какЗатем всегда вызывайте его с круглыми скобками вокруг аргумента типа, например
Конечно, может быть хорошей идеей проиллюстрировать вызовы в комментарии к определению макроса.
источник
UNPACK
делать при таком использовании) UNPACK type name
? Почемуtype
правильно получает тип при использовании) UNPACK type name
? Что, черт возьми, здесь происходит?Сделать это можно как минимум двумя способами. Во-первых, вы можете определить макрос, который принимает несколько аргументов:
если вы это сделаете, вы можете обнаружить, что в конечном итоге определяете больше макросов для обработки большего количества аргументов.
Во-вторых, вы можете заключить аргумент в круглые скобки:
если вы это сделаете, вы можете обнаружить, что лишние круглые скобки портят синтаксис результата.
источник
Это возможно с P99 :
Приведенный выше код эффективно удаляет только последнюю запятую в списке аргументов. Проверьте с
clang -E
(P99 требует компилятора C99).источник
Ответ прост: вы не можете. Это побочный эффект выбора
<...>
аргументов шаблона;<
и>
также появляется в несбалансированных контекстах , поэтому механизм макро не может быть расширен , чтобы справиться с ними , как он обрабатывает круглые скобки. (Некоторые члены комитета, скажем(^...^)
, выступали за другой токен, но им не удалось убедить большинство проблем с использованием<...>
.)источник
(^...^)
это одно счастливое лицо :)