如何 "map" 带有 boost 预处理器的可变参数宏?
How to "map" a variadic macro with boost preprocessor?
假设我有一个宏 F:
#define F(x) /*...*/
和一个带有一个或多个参数的宏 G:
#define G(...) /*...*/
并且我想编写一个宏 H,它接受一个或多个扩展为 G 的参数,并将 F 应用于每个参数:
#define H(...) /* G(F(arg1),F(arg2),...,F(argn)) */
如何用boost.preprocessor实现H?
例如:
#include <boost/preprocessor.hpp>
#define F(x) A x
#define G(...) B __VA_ARGS__ C
#define H(...) ???
H(X, Y, Z)
最后一行应预处理为:
B A X, A Y, A Z C
应该用什么代码替换 ???
?
更新:这个类似的问题C Macros: How to map another macro to variadic arguments? describes how to do it without boost preprocessor, but mentions EVAL
and MAP
from boost preprocessor but I can't seem to find either of those in the documentation: https://www.boost.org/doc/libs/1_78_0/libs/preprocessor/doc/index.html我瞎了吗?
更新 2: 感谢@Artyer,我让它工作了。对于后代,这里是评论中提到的封闭用例的最终解决方案的代码(为结构生成比较运算符):
#pragma once
#include <boost/preprocessor.hpp>
#define COMPARISON_H_STRUCT_MEMBER_LOOKUP(member) (_struct.member)
#define COMPARISON_H_COMMA_SEPARATED_MAP(r, macro, i, elem) \
BOOST_PP_COMMA_IF(i) macro(elem)
#define COMPARISON_H_DECL_TIE_FOR(ClassName, seq) \
inline auto comparison_h_tie_struct(const ClassName& _struct) { \
return std::tie(BOOST_PP_SEQ_FOR_EACH_I(COMPARISON_H_COMMA_SEPARATED_MAP, \
COMPARISON_H_STRUCT_MEMBER_LOOKUP, \
seq)); \
}
#define DECL_STRUCT_EQ_OPS(ClassName, ...) \
COMPARISON_H_DECL_TIE_FOR(ClassName, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
COMPARISON_H_DECL_OP(ClassName, ==) \
COMPARISON_H_DECL_OP(ClassName, !=)
#define DECL_STRUCT_CMP_OPS(ClassName, ...) \
COMPARISON_H_DECL_TIE_FOR(ClassName, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
COMPARISON_H_DECL_OP(ClassName, ==) \
COMPARISON_H_DECL_OP(ClassName, !=) \
COMPARISON_H_DECL_OP(ClassName, <) \
COMPARISON_H_DECL_OP(ClassName, >) \
COMPARISON_H_DECL_OP(ClassName, <=) \
COMPARISON_H_DECL_OP(ClassName, >=)
用法示例:
struct TestStruct {
int member1, member2, member3;
};
DECL_STRUCT_CMP_OPS(TestStruct, member1, member2, member3)
int main() {
TestStruct a, b;
for (int i = 0; i < 27; i++)
for (int j = 0; j < 27; j++) {
a.member1 = (i / 9) % 3;
b.member1 = (j / 9) % 3;
a.member2 = (i / 3) % 3;
b.member2 = (j / 3) % 3;
a.member3 = (i / 1) % 3;
b.member3 = (j / 1) % 3;
assert((i == j) == (a == b));
assert((i != j) == (a != b));
assert((i < j) == (a < b));
assert((i > j) == (a > b));
assert((i <= j) == (a <= b));
assert((i >= j) == (a >= b));
}
}
更新 3:添加了 FOR_EACH_I
修复。
你可以使用BOOST_PP_SEQ_FOR_EACH_I
来做这个“映射”操作:
#define VARIADIC_MAP(r, macro, i, elem) BOOST_PP_COMMA_IF(i) macro(elem)
#define H(...) G(BOOST_PP_SEQ_FOR_EACH_I(VARIADIC_MAP, F, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))
BOOST_PP_COMMA_IF(i)
在除第一个值之外的每个值之前添加一个 ,
,以便扩展到您想要的内容。
假设我有一个宏 F:
#define F(x) /*...*/
和一个带有一个或多个参数的宏 G:
#define G(...) /*...*/
并且我想编写一个宏 H,它接受一个或多个扩展为 G 的参数,并将 F 应用于每个参数:
#define H(...) /* G(F(arg1),F(arg2),...,F(argn)) */
如何用boost.preprocessor实现H?
例如:
#include <boost/preprocessor.hpp>
#define F(x) A x
#define G(...) B __VA_ARGS__ C
#define H(...) ???
H(X, Y, Z)
最后一行应预处理为:
B A X, A Y, A Z C
应该用什么代码替换 ???
?
更新:这个类似的问题C Macros: How to map another macro to variadic arguments? describes how to do it without boost preprocessor, but mentions EVAL
and MAP
from boost preprocessor but I can't seem to find either of those in the documentation: https://www.boost.org/doc/libs/1_78_0/libs/preprocessor/doc/index.html我瞎了吗?
更新 2: 感谢@Artyer,我让它工作了。对于后代,这里是评论中提到的封闭用例的最终解决方案的代码(为结构生成比较运算符):
#pragma once
#include <boost/preprocessor.hpp>
#define COMPARISON_H_STRUCT_MEMBER_LOOKUP(member) (_struct.member)
#define COMPARISON_H_COMMA_SEPARATED_MAP(r, macro, i, elem) \
BOOST_PP_COMMA_IF(i) macro(elem)
#define COMPARISON_H_DECL_TIE_FOR(ClassName, seq) \
inline auto comparison_h_tie_struct(const ClassName& _struct) { \
return std::tie(BOOST_PP_SEQ_FOR_EACH_I(COMPARISON_H_COMMA_SEPARATED_MAP, \
COMPARISON_H_STRUCT_MEMBER_LOOKUP, \
seq)); \
}
#define DECL_STRUCT_EQ_OPS(ClassName, ...) \
COMPARISON_H_DECL_TIE_FOR(ClassName, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
COMPARISON_H_DECL_OP(ClassName, ==) \
COMPARISON_H_DECL_OP(ClassName, !=)
#define DECL_STRUCT_CMP_OPS(ClassName, ...) \
COMPARISON_H_DECL_TIE_FOR(ClassName, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
COMPARISON_H_DECL_OP(ClassName, ==) \
COMPARISON_H_DECL_OP(ClassName, !=) \
COMPARISON_H_DECL_OP(ClassName, <) \
COMPARISON_H_DECL_OP(ClassName, >) \
COMPARISON_H_DECL_OP(ClassName, <=) \
COMPARISON_H_DECL_OP(ClassName, >=)
用法示例:
struct TestStruct {
int member1, member2, member3;
};
DECL_STRUCT_CMP_OPS(TestStruct, member1, member2, member3)
int main() {
TestStruct a, b;
for (int i = 0; i < 27; i++)
for (int j = 0; j < 27; j++) {
a.member1 = (i / 9) % 3;
b.member1 = (j / 9) % 3;
a.member2 = (i / 3) % 3;
b.member2 = (j / 3) % 3;
a.member3 = (i / 1) % 3;
b.member3 = (j / 1) % 3;
assert((i == j) == (a == b));
assert((i != j) == (a != b));
assert((i < j) == (a < b));
assert((i > j) == (a > b));
assert((i <= j) == (a <= b));
assert((i >= j) == (a >= b));
}
}
更新 3:添加了 FOR_EACH_I
修复。
你可以使用BOOST_PP_SEQ_FOR_EACH_I
来做这个“映射”操作:
#define VARIADIC_MAP(r, macro, i, elem) BOOST_PP_COMMA_IF(i) macro(elem)
#define H(...) G(BOOST_PP_SEQ_FOR_EACH_I(VARIADIC_MAP, F, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))
BOOST_PP_COMMA_IF(i)
在除第一个值之外的每个值之前添加一个 ,
,以便扩展到您想要的内容。