【问题标题】:Preprocessor: Concatenate string to each argument in __VA_ARGS__预处理器:将字符串连接到 __VA_ARGS__ 中的每个参数
【发布时间】:2017-06-11 00:19:47
【问题描述】:

我想将一个字符串化的宏参数附加到可变参数宏中的每个元素。我想我知道我需要什么,但我还没有想出一个可行的解决方案。给定一个可变参数宏,例如:

#define FIELD_DECLARATION(NAME, OTHER_FIELD, ...)

FIELD_DECLARATION(First, Thing)
FIELD_DECLARATION(Second, Thing, Thing, Nothing)

我想生成:

field_First = {ThingArg};
field_Second = {ThingArg, ThingArg, NothingArg};

我想我需要的是递归地继续扩展 __VA_ARGS__ 直到它到达没有元素,并在进行扩展时附加 "Arg"。最后,将结果传递给另一个可变参数宏,该宏生成以逗号分隔的参数列表。

我已经尝试过了,但它不起作用(我描述的也不是这样):

#define UNPACK_VA_1(A1) A1 ## Arg
#define UNPACK_VA_2(A1, A2) UNPACK_VA_1(A1), UNPACK_VA_1(A2)
#define UNPACK_VA_3(A1, A2, A3) UNPACK_VA_2(A1, A2), UNPACK_VA_1(A3)
#define UNPACK_VA_4(A1, A2, A3, A4) UNPACK_VA_2(A1, A2), UNPACK_VA_2(A3, A4)
#define UNPACK_VA(...) UNPACK_VA_4(__VA_ARGS__)

#define FOO(x, y, ...) UNPACK_VA(__VA_ARGS__)
FOO(One, Two, Three, Four, Five, Six)

虽然这在一定程度上可行,但我无法提出可扩展的解决方案。如果有人能提供一盏灯,那就太好了。

【问题讨论】:

  • 你看过 Boost::Preprocessor 吗?如果可以做到,那就可以做到。
  • 这是一个 C 项目,所以不能有 Boost。但是,我可能会仔细观察并模仿他们的所作所为。好点,谢谢!我想我正在寻找类似于 for-each 关于可变参数的东西,其中有关于 SO 的示例。
  • Boost::Preprocessor 在 C 和 C++ 之间是语言中立的。你用 C++ 和 C 标记了这个问题。这是一个错误吗?
  • 对,我刚刚从标签列表中删除了 C++。由于它是同一个预处理器,我认为 C++ 和 C 程序员都可以看到这个问题。我以前从未在 C 项目中尝试过 Boost.Preprocessor,我很快就会尝试。同时,我发现并尝试了this answer,扩展数量减少了。我考虑这样做,但我必须先将其发送以供审核。
  • “同时,我已经找到并尝试过(描述 MSVC 内容的链接)” ...等等...您在使用 MSVC 吗?如果是这样,那将有助于提及。 MSVC 没有标准的预处理器,所以语义都是不同的。我通常会假设“c 预处理器”指的是标准的(几乎所有其他主要编译器都是标准的)

标签: c macros c-preprocessor


【解决方案1】:

这是一种可扩展的方法。首先,一些通用的实用宏:

#define EVAL(...) __VA_ARGS__
#define VARCOUNT(...) \
   EVAL(VARCOUNT_I(__VA_ARGS__,9,8,7,6,5,4,3,2,1,))
#define VARCOUNT_I(_,_9,_8,_7,_6,_5,_4,_3,_2,X_,...) X_
#define GLUE(X,Y) GLUE_I(X,Y)
#define GLUE_I(X,Y) X##Y
#define FIRST(...) EVAL(FIRST_I(__VA_ARGS__,))
#define FIRST_I(X,...) X
#define TUPLE_TAIL(...) EVAL(TUPLE_TAIL_I(__VA_ARGS__))
#define TUPLE_TAIL_I(X,...) (__VA_ARGS__)

#define TRANSFORM(NAME_, ARGS_) (GLUE(TRANSFORM_,VARCOUNT ARGS_)(NAME_, ARGS_))
#define TRANSFORM_1(NAME_, ARGS_) NAME_ ARGS_
#define TRANSFORM_2(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_1(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_3(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_2(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_4(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_3(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_5(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_4(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_6(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_5(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_7(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_6(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_8(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_7(NAME_,TUPLE_TAIL ARGS_)
#define TRANSFORM_9(NAME_, ARGS_) NAME_(FIRST ARGS_),TRANSFORM_8(NAME_,TUPLE_TAIL ARGS_)

在语义上,VARCOUNT 计算参数; GLUE是典型的间接贴; FIRST 提取第一个参数; EVAL 扩展为它的参数(意图评估),TUPLE_TAIL 返回一个元组的尾部(即,它丢弃第一个参数)。

TRANSFORM 这里是主要思想; TRANSFORM(FOO,(X,Y,Z)) 接受一个元组 (X,Y,Z)(FOO(X),FOO(Y),FOO(Z))

就位,这是专用代码:

#define Z_ARG(X) GLUE(X,Arg)
#define MAKE_INITIALIZER(...) { __VA_ARGS__ }
#define FIELD_DECLARATION(FNAME_, ...) \
   GLUE(field_, FNAME_) = EVAL(MAKE_INITIALIZER TRANSFORM(Z_ARG, (__VA_ARGS__)));

鉴于上述情况,这应该是可读的,但只是为了解释... Z_ARGArg 粘贴到一个项目; MAKE_INITIALIZER 将预处理器元组转换为初始化列表; FIELD_DECLARATION 是你的宏。请注意,EVAL 包装了 MAKE_INITIALIZER/transformed 元组,因此它实际上会调用该宏。

注意:将EVAL 移到顶部并在更多地方使用它,这样在 MSVC 中也可以使用。

Demonstration, original code

Demonstration, current code

【讨论】:

  • 这太棒了,谢谢!我会尝试将TRANSFORM_N 宏隐藏在另一个头文件中的某个位置。我必须了解它是如何扩展的。在我的尝试中,我想不出一个模式匹配宏,所以我必须将 N 个参数传递给我的宏。但是,这个field 至少可以有 3 个参数(所以上限是未知的,这就是我想要创建的)。我将不得不详细研究你的部分示例,以更好地理解扩展。
  • 我很想看到一个不可扩展的解决方案,哈哈。 +1 虽然
  • 这里 EVAL 宏的作用是什么?
  • @bremen_matt 这是一个专门针对 MS's preprocessor (godbolt) 的间接步骤,由于它处理 __VA_ARGS__ 的方式需要额外的帮助(即,即使扩展中有逗号,也将其视为单个参数)。
  • 男人。宏...无论如何,供我个人参考,这是一个我认为更清晰的清理版本。由于我真的不想调查的原因,您仍然需要 EVAL 宏一次:godbolt.org/z/jD2BHp
【解决方案2】:

我已经在 Visual Studio C++ 上测试了上面的代码,有一些问题和编译器显示错误。 一些专门针对 VA_ARGS 的学徒是不必要的,而且在某些地方我们必须使用 VA_ARGS.. . 而不是 'Args' 的正确代码并且还扩展到 60 个输入项是:

#ifndef __MACROS__
#define __MACROS__
#define EVAL(...) __VA_ARGS__
#define VARCOUNT(...) \
   EVAL(VARCOUNT_I(__VA_ARGS__,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,))
#define VARCOUNT_I(_,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,X_,...) X_
#define GLUE(X,Y) GLUE_I(X,Y)
#define GLUE_I(X,Y) X##Y
#define FIRST(...) EVAL(FIRST_I(__VA_ARGS__,))
#define FIRST_I(X,Args) X
#define TUPLE_TAIL(...) EVAL(TUPLE_TAIL_I(__VA_ARGS__))
#define TUPLE_TAIL_I(X,...) __VA_ARGS__

#define TRANSFORM(NAME_, ...) GLUE(TRANSFORM_,VARCOUNT(__VA_ARGS__))(NAME_, __VA_ARGS__)
#define TRANSFORM_1(NAME_, ARGS_) NAME_ (ARGS_)
#define TRANSFORM_2(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_1(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_3(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_2(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_4(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_3(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_5(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_4(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_6(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_5(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_7(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_6(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_8(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_7(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_9(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_8(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_10(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_9(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_11(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_10(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_12(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_11(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_13(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_12(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_14(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_13(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_15(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_14(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_16(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_15(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_17(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_16(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_18(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_17(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_19(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_18(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_20(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_19(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_21(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_20(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_22(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_21(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_23(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_22(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_24(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_23(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_25(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_24(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_26(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_25(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_27(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_26(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_28(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_27(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_29(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_28(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_30(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_29(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_31(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_30(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_32(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_31(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_33(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_32(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_34(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_33(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_35(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_34(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_36(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_35(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_37(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_36(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_38(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_37(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_39(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_38(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_40(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_39(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_41(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_40(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_42(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_41(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_43(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_42(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_44(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_43(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_45(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_44(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_46(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_45(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_47(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_46(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_48(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_47(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_49(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_48(NAME_,TUPLE_TAIL( ARGS_))

#define TRANSFORM_50(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_49(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_51(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_50(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_52(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_51(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_53(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_52(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_54(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_53(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_55(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_54(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_56(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_55(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_57(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_56(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_58(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_57(NAME_,TUPLE_TAIL( ARGS_))
#define TRANSFORM_59(NAME_, ARGS_) NAME_(FIRST (ARGS_)) TRANSFORM_58(NAME_,TUPLE_TAIL( ARGS_))
#endif

【讨论】:

    猜你喜欢
    • 2011-01-08
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多