Использование препроцессора 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_SEQUENCESBOOST_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 принимает последовательность и возвращает ее элементы, разделенные запятыми.

Предварительно обработано на Coliru

Обновление: отредактированный ответ на основе комментариев. Сейчас звонит 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>)
Другие вопросы по тегам