Say I have a macro F:
#define F(x) /*...*/
and a macro G that takes one or more arguments:
#define G(...) /*...*/
and I want to write a macro H that takes one or more arguments that expands to G with F applied to each argument:
#define H(...) /* G(F(arg1),F(arg2),...,F(argn)) */
How can H be implemented with boost.preprocessor ?
For example:
#include <boost/preprocessor.hpp>
#define F(x) A x
#define G(...) B __VA_ARGS__ C
#define H(...) ???
H(X, Y, Z)
The final line should preprocess to:
B A X, A Y, A Z C
What code should replace the ???
?
Update: This similar question 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 Am I blind?
Update 2: I've got it working thanks to @Artyer. For posterity, here is the code of the final solution of the enclosing use case mentioned in the comments (generating comparison operators for a struct):
#pragma once
#include <boost/preprocessor.hpp>
#define COMPARISON_H_STRUCT_MEMBER_LOOKUP(member) (_struct.member)
#define COMPARISON_H_COMMA_SEPARATED_MAP(r, macro, elem) \
BOOST_PP_COMMA_IF(BOOST_PP_DEC(r)) 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(COMPARISON_H_COMMA_SEPARATED_MAP, \
COMPARISON_H_STRUCT_MEMBER_LOOKUP, \
seq)); \
}
#define COMPARISON_H_DECL_OP(ClassName, op) \
inline bool operator op(const ClassName& a, const ClassName& b) { \
return comparison_h_tie_struct(a) op comparison_h_tie_struct(b); \
}
#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, >=)
Example usage:
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));
}
}
CodePudding user response:
You can use BOOST_PP_SEQ_FOR_EACH
to do this "mapping" operation:
#define VARIADIC_MAP(r, macro, elem) BOOST_PP_COMMA_IF(BOOST_PP_DEC(r)) macro(elem)
#define H(...) G(BOOST_PP_SEQ_FOR_EACH(VARIADIC_MAP, F, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))
The BOOST_PP_COMMA_IF(BOOST_PP_DEC(r))
prepends a ,
before every value except the first so this expands to what you want.