Можно ли передать инициализатор, заключенный в скобки, в качестве макропараметра?
У меня есть функция, которую я вызываю так:
literal<long[2]>({1, 2});
Я хочу написать макрос, который расширяется до этого утверждения, например:
MYMACRO(long[2], {1, 2})
К сожалению, препроцессор не знает о скобках, поэтому он видит три аргумента (второй и третий - {1
и 2}
соответственно).
Это известное ограничение препроцессора, и самое простое решение часто заключается в добавлении дополнительных скобок, если это возможно, в макро-вызов.
Но в этом случае размещение в скобках вставленного в скобки инициализатора изменит его значение:
literal<long[2]>(({1, 2}));
(g++ 4.8) error: left operand of comma operator has no effect [-Werror=unused-value]
Является ли это ошибкой GCC или исправлена по дизайну? Есть ли способ сделать то, что я хочу?
Update
Вероятно, я должен был быть более ясным в формулировке исходных вопросов. Препроцессор не изменился навсегда (даже переменные макросы долгое время были расширением GCC). Практические обходные пути в этом случае полезны, но они также очень хорошо известны, а не то, что я хочу получить.
Я действительно хочу знать, было ли что-то добавлено в С++ 11 специально для решения этой проблемы (или это был надзор?). Причудливая обработка фигурных скобок в макросочетаниях кажется сейчас гораздо более серьезной проблемой, учитывая значительно расширенное использование списков, заключенных в фигурные скобки на всем языке.
Меня особенно раздражает тот факт, что размещение круглых скобок вокруг списка инициализаторов, заключенных в скобки, меняет способ его анализа при использовании в качестве параметра функции. Есть ли какой-либо другой параметр для вызова функции, который не может быть заключен в скобки? Это похоже на адский адский случай при написании макросов, которые передают параметры функциям.
Я действительно надеюсь, что кто-то может указать, что это ошибка GCC, или объяснить, почему поместить скобки вокруг списка инициализаторов, заключенных в скобки, необходимо изменить его значение.
Ответы
Ответ 1
Вы можете использовать __VA_ARGS__
:
#define MYMACRO(T,...) literal<T>(__VA_ARGS__);
Если у вас есть больше параметров, вы можете использовать косвенные действия:
#define UNWRAP(...) __VA_ARGS__
#define MYMACRO(T,A) literal<T>(UNWRAP A);
и теперь вы можете использовать
MYMACRO( long[2], ({1, 2}) )
Обновленный ответ
Вы также можете, если хотите, заменить фигурные скобки в вызове макроса круглыми скобками:
#define BRACED_INIT_LIST(...) {__VA_ARGS__}
#define MYMACRO(T,A) literal<T>(BRACED_INIT_LIST A);
и вызовите
MYMACRO( long[2], (1, 2) )
который IMHO соответствует типичным стилям макро-вызова.
Некоторые слова по другим вопросам: препроцессор ничего не знает о языке (C, С++, С++ 11) и, следовательно, не должен заботиться о специальном значении символов. Он отслеживает круглые скобки, но почти все остальное - всего лишь токены.
Я также считаю, что это не является надзором со стороны стандартного комитета, поскольку основное внимание следует уделять тому, чтобы использование препроцессора было излишним для большинства случаев. Рассматривали ли вы другие (не-макро) методы для реализации MYMACRO
? Кроме того, возможности для оставшихся прецедентов (как показано выше), безусловно, возможны.
Наконец, это, конечно, не ошибка в GCC, поскольку компилятор просто реализует то, что говорит стандарт.