Как разобрать токены, разделенные пробелами в препроцессоре C++?
Я занимаюсь метапрограммированием препроцессора, и мне нужен способ конвертации f(a b)
в g(a,b)
в препроцессоре C++. поскольку a
а также b
два жетона в C++
Кажется возможным найти способ разделить их. Тем не менее, после нескольких часов работы все еще нет решения этой проблемы.
Любая сторонняя библиотека, включая boost::preprocessor
приветствуется, учитывая, что эти библиотеки работают в процессе предварительной обработки.
Кроме того, есть ли способ разделить произвольные токены? например const T&
следует преобразовать в const
, T
, &
1 ответ
Это невозможно.
Для ограниченного числа токенов это возможно, но у вас должен быть словарь всех возможных токенов, которые вы хотите обработать. Весь процесс использовался в разделе «Заменить пробелы подчеркиваниями в макросе?»и здесь я перепишу это без поиска просто ради интереса.
Как правило, вы можете объединить начало списка с помощью префикса, напримерWORD_##__VA_ARGS__
где__VA_ARGS__="a b c"
. Затем имея#define WORD_a a,
вы можете отделить ведущее слово от остальных. Повторяя такой процесс для каждого токена, вы можете создать список отдельных токенов.
// dictionary of all words
#define WORD_
#define WORD_a a,
#define WORD_b b,
#define WORD_c c,
#define WORD_d d,
#define TOKENIZE_1(a) WORD_##a
#define TOKENIZE_2(a,...) a, TOKENIZE_1(__VA_ARGS__)
#define TOKENIZE_3(a,...) a, TOKENIZE_2(__VA_ARGS__)
#define TOKENIZE_4(a,...) a, TOKENIZE_3(__VA_ARGS__)
#define TOKENIZE_5(a,...) a, TOKENIZE_4(__VA_ARGS__)
#define TOKENIZE_N(_5,_4,_3,_2,_1,N,...) TOKENIZE##N
#define TOKENIZE(...) TOKENIZE_N(__VA_ARGS__,_5,_4,_3,_2,_1)(__VA_ARGS__)
#define REMOVELAST_1(a)
#define REMOVELAST_2(a,...) a
#define REMOVELAST_3(a,...) a, REMOVELAST_2(__VA_ARGS__)
#define REMOVELAST_4(a,...) a, REMOVELAST_3(__VA_ARGS__)
#define REMOVELAST_5(a,...) a, REMOVELAST_4(__VA_ARGS__)
#define REMOVELAST_N(_5,_4,_3,_2,_1,N,...) REMOVELAST##N
#define REMOVELAST(...) REMOVELAST_N(__VA_ARGS__,_5,_4,_3,_2,_1)(__VA_ARGS__)
#define SPACES_TO_ARGS(...) REMOVELAST(TOKENIZE(TOKENIZE(TOKENIZE(TOKENIZE(__VA_ARGS__)))))
#define f(spaceargs) g(SPACES_TO_ARGS(spaceargs))
f(a b) to g(a, b)
f(a b c) to g(a, b, c)
f(a b c d) to g(a, b, c, d)
Более того, есть ли способ разделить произвольные токены?
Нет, это невозможно.
Любая сторонняя библиотека, включая boost::preprocessor, приветствуется, поскольку эти библиотеки работают в процессе предварительной обработки.
я использовалBOOST_PP_WHILE
чтобы сделать его немного более абстрактным для любого количества аргументов (вплоть до пределов повышения).
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/control/while.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/seq/to_tuple.hpp>
#include <boost/preprocessor/seq/pop_back.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/facilities/is_empty.hpp>
#include <boost/preprocessor/logical/not.hpp>
// dictionary of all words
#define WORD_
#define WORD_a a,
#define WORD_b b,
#define WORD_c c,
#define WORD_d d,
#define ADDWORD2(a) WORD_##a
#define ADDWORD(r, _, a) ADDWORD2(a)
#define TOKENIZE_OP(d, list) \
BOOST_PP_VARIADIC_TO_SEQ(BOOST_PP_SEQ_FOR_EACH(ADDWORD, _, list))
#define SEQ_LAST(state) \
BOOST_PP_SEQ_ELEM(BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(state)), state)
#define TOKENIZE_PRED(d, state) \
BOOST_PP_NOT(BOOST_PP_IS_EMPTY(SEQ_LAST(state)))
#define SPACES_TO_ARGS(...) \
BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_POP_BACK( \
BOOST_PP_WHILE(TOKENIZE_PRED, TOKENIZE_OP, (__VA_ARGS__)) \
))
#define f(spaceargs) g SPACES_TO_ARGS(spaceargs)
f(a b)
f(a b c)
f(a b c d)