如何 "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) 在除第一个值之外的每个值之前添加一个 ,,以便扩展到您想要的内容。