使用boost预处理器迭代地调用可变参数模板

时间:2016-01-27 08:05:15

标签: c++ boost macros boost-preprocessor

假设我有一个可变参数模板:

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预处理器来减少我必须编写的代码。

请给我一些建议,帮助我编写这样的宏。

2 个答案:

答案 0 :(得分: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之后,您有一系列序列:

    (适用(浮子)(INT)(字符串)(载体)的)((INT)(字符串)(载体)的)( (字符串)(载体)的)((向量)的

  • BOOST_PP_SEQ_FOR_EACH使用序列序列中的每个元素调用CALL_MACRO

  • 最后BOOST_PP_SEQ_ENUM接受一个序列并返回以逗号分隔的元素。

Preprocessed on Coliru

答案 1 :(得分: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的实时演示。

有一点需要注意的是,扩展与OP指定的方向相反,即:

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