Variadic макросы - PullRequest
       40

Variadic макросы

3 голосов
/ 09 июня 2011

Есть ли способ написать макрос так:

#define G(x1, x2, ... , xn) f(x1), f(x2), ... , f(xn)

Или мне нужно определить это для каждого человека n?

C ++ 0x ответы в порядке.

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

Цель: : Итак, я могу сделать что-то вроде следующего:

#define MAKE_TUPLE(x1, x2, ... , xn) mytuple<decltype((x1)), decltype((x2)), ... , decltype((xn))>{x1, x2, ... , xn}

Таким образом, этот mytuple может быть создан без перемещений и копий, а также без ненужных ссылок на временные объекты, которые могли быть созданы на месте с использованием совокупной конструкции.

Ответы [ 3 ]

5 голосов
/ 10 июня 2011

Цель : [лишено описания вновь неправильного подхода]. Таким образом, этот mytuple может быть создан без перемещений и копий, а также без ненужных ссылок на временные файлы, которые могли бы быть созданы на месте с использованием совокупной конструкции.

Вы уточнили свои требования в комментарии

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

Вы были на неверном пути. Следующее не является макросом, не создает движений или копий (не более чем макрос) и не имеет ненужных ссылок на временные ссылки (не уверен, что означает последняя часть ваших требований, но я думаю, что мы можем прояснить это итеративно). Это так же быстро, как «обычная передача аргументов», так как больше ничего не делает.

template<typename ...T>
mytuple<T...> make_tuple(T&&... t) {
  return mytuple<T...>{std::forward<T>(t)...};
}

Это поведение отличается от последовательности decltype выражений, которые вы даете, относительно типа аргумента X

  • Prvalues ​​передаются в кортеж как X
  • Значения X передаются в кортеж как X
  • Значения L передаются в кортеж как X&

Ваш макрос ведет себя по-другому

  • Prvalues ​​передаются в кортеж как X
  • Значения X передаются в кортеж как X&&
  • L-значения передаются в кортеж как X&

Обратите внимание на среднюю часть - вы склонны к висящим ссылкам, если только время жизни вашего кортежа не всегда меньше времени жизни всех аргументов, но затем сохраняете prvalues, так как X создает ненужную копию. Используйте mytuple<T&&...> в моем коде для постоянного использования ссылок, как показано ниже

  • Prvalues ​​передаются в кортеж как X&&
  • Значения X передаются в кортеж как X&&
  • L-значения передаются в кортеж как X&
5 голосов
/ 09 июня 2011

Если вы хотите использовать слегка неуклюжий синтаксис, вы можете использовать последовательности Boost.Preprocessor:

#include <boost/preprocessor.hpp>

#define G(args) BOOST_PP_SEQ_FOR_EACH_I(G_GENF, x, args)
#define G_GENF(r, data, i, elem) \
    BOOST_PP_COMMA_IF(BOOST_PP_NOT_EQUAL(i, 0)) f(elem)

Использование:

G((a))
G((b)(c))
G((d)(e)(f))

Результат:

f(a)
f(b) , f(c)
f(d) , f(e) , f(f)

Если вам нужен синтаксис G(a, b, c), то, поскольку замена макросов не является рекурсивной, я думаю, вам, вероятно, понадобится один макрос на число аргументов, которые вы собираетесь передать.Вы все еще можете делегировать эти макросы из одного макроса, используемого в другом месте вашего источника.Рассмотрим:

// Utility for counting the number of args in the __VA_ARGS__ pack:
#define PP_NARGS(...) PP_NARGS2(__VA_ARGS__, PP_NARGS_COUNT())
#define PP_NARGS2(...) PP_NARGS_IMPL(__VA_ARGS__)
#define PP_NARGS_IMPL(x1, x2, x3, N, ...) N
#define PP_NARGS_COUNT() 3, 2, 1, 0, ERROR

// Macros to delegate to concrete, defined-arity implementations:
#define XF(count, ...) XF_IMPL (count, __VA_ARGS__)
#define XF_IMPL(count, ...) XF_ ## count (__VA_ARGS__)

// Defined-arity implementations:
#define XF_1(x1)         f(x1)
#define XF_2(x1, x2)     f(x1), f(x2)
#define XF_3(x1, x2, x3) f(x1), f(x2), f(x3)

// Delegation macro; this is the only macro you need to call from elsewhere:
#define G(...) XF(PP_NARGS(__VA_ARGS__), __VA_ARGS__)    

Использование:

G(a)
G(b, c)
G(d, e, f)

Результат:

f(a)
f(b), f(c)
f(d), f(e), f(f)

Это, безусловно, можно обобщить, и некоторые библиотеки утилит препроцессора уже могут иметь некоторые средствасделать это, но это демонстрирует, как это можно сделать.(Я не знаком ни с какими библиотеками препроцессора C99 / C ++ 0x, поэтому не могу порекомендовать одну из них.)

0 голосов
/ 09 июня 2011

Насколько я помню, библиотека Boost Preprocessor может делать это даже для C ++ 98.

Однако макросы - это зло, и их лучше избегать.

Вместо этого думайтео таких вещах, как

Type const values[] = {x1, x2, x3, ... xn};

for( int i = 0;  i < countOf( values );  ++i )
{
    f( values[i] );
}

Приветствия и hth.

...