2016-01-27 2 views
0

Предположим, у меня есть VARIADIC шаблон:Использование наддува препроцессор называть VARIADIC шаблону итеративно

template<typename... Args> 
class Foo; 

Этот VARIADIC шаблон создает другой шаблон рекурсивно до тех пор, пока не достигнет одного аргумента 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 для сокращения кода, который я должен написать.

Пожалуйста, предложите мне несколько советов, которые помогут мне написать такой макрос.

+0

Это возможно точно, но это серьезно звучит как [XY Проблема] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) , – Rumburak

+0

Являются ли макросы 'Bar' и' Macro' разными? И вы хотите, чтобы макрос «Макро» вызывался для каждого расширения вызова вариационного шаблона? – RobClucas

+0

Спасибо за ваш совет. Хотя я полностью не согласен с вами, но я изменил вопрос, чтобы избежать проблемы с XY. – MohsenTamiz

ответ

1

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

#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>) 
  • вы изначально имеют VARIADIC данные: 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 у вас есть последовательность последовательностей:

    ( (поплавок) (INT) (строка) (вектор) ) ( (INT) (строка) (вектор) ) ( (строка) (вектор) ) ( (вектор) )

  • BOOST_PP_SEQ_FOR_EACH вызовы CALL_MACRO с каждым элементом в последовательности последовательностей.

  • И, наконец, BOOST_PP_SEQ_ENUM принимает последовательность и возвращает ее элементы, разделенные запятыми.

Preprocessed on Coliru

1

Обновление: Отредактированный ответ на основе комментариев. Теперь вызывает 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.

Одна вещь, чтобы отметить, что расширение находится в противоположном направлении к тому, что указано ОП, то есть:

Macro(Foo<>) 
Macro(Foo<double>) 
Macro(Foo<float, double>) 
Macro(Foo<int, float, double>) 
+0

Может быть, я должен больше рассказать о «Макро», это еще один макрос, который я должен использовать. В частности, это макрос 'BOOST_EXPORT_CLASS', который я хочу использовать для экспорта каждого типа класса. Поэтому я думаю, что ваш ответ недействителен, это шаблон и не то, что я хотел. – MohsenTamiz

+1

@nabla Вы предполагаете, что 'Macro' - это то, что можно свести к функции (' constexpr' или иначе), что, похоже, не относится к OP. Например, макрос может быть расширен до объявления. – Elektito

+0

@MohsenTamiz, извините, я сделал предположение, основанное на том, что я понял из вопроса. См. Обновленный ответ - надеюсь, это делает то, что вы хотите. Поскольку я не пробовал это с повышением, пожалуйста, дайте мне знать, если это сработает. – RobClucas