Использование препроцессора boost для итеративного вызова шаблона variadic
Предположим, у меня есть шаблон variadic:
template<typename... Args>
class Foo;
Этот вариационный шаблон генерирует другой шаблон рекурсивно, пока не достигнет одного аргумента Foo
на последнем уровне. Теперь я хочу иметь макрос, например Bar(...)
который, когда я называю это, я получаю что-то вроде этого:
Bar(float, int, string, vector<int>)
// expands to
Macro(Foo<float, int, string, vector<int>>)
Macro(Foo<int, string, vector<int>>)
Macro(Foo<string, vector<int>>)
Macro(Foo<vector<int>>)
Который Macro(...)
еще один макрос для того, чтобы что-то делать в этом классе. Я надеюсь, что смогу использовать Boost Preprocessor для уменьшения кода, который я должен написать.
Пожалуйста, предложите мне несколько советов, которые помогут мне написать такой макрос.
2 ответа
Я не знаю, является ли это лучшим подходом к решению вашей проблемы, но он делает то, что вы хотите:
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#define CALL_MACRO(_,__,SEQ) Macro(Foo<BOOST_PP_SEQ_ENUM(SEQ)>)
#define GENERATE_MACRO_INVOCATIONS(SEQS) BOOST_PP_SEQ_FOR_EACH(CALL_MACRO,_,SEQS)
#define GENERATE_DESCENDING_SEQUENCES(_,INDEX,DATA) (BOOST_PP_SEQ_REST_N(INDEX,DATA))
#define BAR_IMPL(SEQ) GENERATE_MACRO_INVOCATIONS(BOOST_PP_REPEAT_FROM_TO(0,BOOST_PP_SEQ_SIZE(SEQ),GENERATE_DESCENDING_SEQUENCES, SEQ))
#define Bar(...) BAR_IMPL(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
Bar(float, int, string, vector<int>)
- У вас изначально есть переменные данные:
float, int, string, vector<int>
, BOOST_PP_VARIADIC_TO_SEQ
превращает его в:(float)(int)(string)(vector<int>)
BOOST_PP_REPEAT_FROM_TO
вызывает макросGENERATE_DESCENDING_SEQUENCES
BOOST_PP_SEQ_SIZE(SEQ)
раз с последовательностью в качестве данных и индекса, который начинается с 0.BOOST_PP_SEQ_REST_N(INDEX,DATA)
удаляетINDEX
первые элементы изDATA
и возвращает остальное. Этот результат помещается в пару скобок.После вызова REPEAT у вас есть последовательность последовательностей:
((float) (int) (строка) (вектор)) ((int) (строка) (вектор)) ((строка) (вектор)) ((вектор))
BOOST_PP_SEQ_FOR_EACH
звонкиCALL_MACRO
с каждым элементом в последовательности последовательностей.- И наконец
BOOST_PP_SEQ_ENUM
принимает последовательность и возвращает ее элементы, разделенные запятыми.
Обновление: отредактированный ответ на основе комментариев. Сейчас звонит BOOST_EXPORT_CLASS
макрос вместо macro()
Функция, которую я определил. Я не проверял это с BOOST_EXPORT_CLASS
Тем не менее, я сделал симуляцию, получив доступ к типу Foo<...>
на каждом уровне расширения шаблона. Мне удалось получить доступ к каждому из различных типов для разных расширений, поэтому я предполагаю, что все BOOST_EXPORT_CLASS
должно работать.
Я думаю, что это сейчас делает то, что вы хотите:
#define BAR(...) Foo<__VA_ARGS__>()
// Variadic definition of Foo
template <typename... Args>
struct Foo;
// Specialize Foo for the case that there is at least on template parameter
template <typename Arg, typename... Args>
struct Foo<Arg, Args...> : Foo<Args...> {
using type = Foo<Arg, Args...>;
Foo() : Foo<Args...>(){
BOOST_EXPORT_CLASS(type)
}
};
// Terminating case for Foo
template <>
struct Foo<> {
using type = Foo<>;
Foo() { BOOST_EXPORT_CLASS(type) }
};
int main() {
BAR(int, float, double);
}
Чтобы проверить, что это должно работать теоретически, я определил следующий макрос:
#define MACRO(x) test<x>();
И заменил BOOST_EXPORT_CLASS(type)
с MACRO(type)
, Функция test
является следующим:
template <typename T>
void test() {
std::cout << typeid(T).name() << "\n";
}
Выполнение кода напечатало следующее (я добавил комментарии), которое показывает, что шаблоны раскрываются в макросе и должны отображаться BOOST_EXPORT_CLASS
как показано в вопросе:
3FooIJEE // Foo<>
3FooIJdEE // Foo<double>
3FooIJfdEE // Foo<float, double>
3FooIJifdEE // Foo<int, float, double>
Вот живая демонстрация кода Live Demo.
Следует отметить, что расширение происходит в направлении, противоположном указанному в OP, т.е.
Macro(Foo<>)
Macro(Foo<double>)
Macro(Foo<float, double>)
Macro(Foo<int, float, double>)