使用 boost 预处理器迭代调用可变参数模板
Using boost preprocessor to call a variadic template iteratively
假设我有一个可变参数模板:
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(...)
是另一个用于在此 class 上执行某些操作的宏。我希望能够使用 Boost 预处理器来减少我必须编写的代码。
请给我一些提示,帮助我编写这样的宏。
更新:根据评论编辑了答案。现在调用 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>)
我不知道这是否是解决您问题的最佳方法,但这可以满足您的需求:
#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)
从 DATA
中删除第一个元素 INDEX
,其余的 returns。此结果放在一对括号内。
在调用 REPEAT 之后,您有一系列序列:
((浮点数)(整数)(字符串)(向量))((整数)(字符串)(向量))((字符串)(向量))((向量))
BOOST_PP_SEQ_FOR_EACH
对序列序列中的每个元素调用 CALL_MACRO
。
- 最后
BOOST_PP_SEQ_ENUM
取一个序列,returns 其元素用逗号分隔。
假设我有一个可变参数模板:
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(...)
是另一个用于在此 class 上执行某些操作的宏。我希望能够使用 Boost 预处理器来减少我必须编写的代码。
请给我一些提示,帮助我编写这样的宏。
更新:根据评论编辑了答案。现在调用 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>)
我不知道这是否是解决您问题的最佳方法,但这可以满足您的需求:
#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)
从DATA
中删除第一个元素INDEX
,其余的 returns。此结果放在一对括号内。在调用 REPEAT 之后,您有一系列序列:
((浮点数)(整数)(字符串)(向量))((整数)(字符串)(向量))((字符串)(向量))((向量))
BOOST_PP_SEQ_FOR_EACH
对序列序列中的每个元素调用CALL_MACRO
。- 最后
BOOST_PP_SEQ_ENUM
取一个序列,returns 其元素用逗号分隔。