gpt4 book ai didi

c++ - 将宏传递给另一个宏而不是直接传递东西时出现不需要的额外 "empty"参数

转载 作者:行者123 更新时间:2023-12-03 18:16:31 25 4
gpt4 key购买 nike

问题(简​​明)

(后面是完整的最小代码)不知何故,当我将一个简单的参数列表传递给我的宏时,一切都很好。

#pragma message STRINGIZE( ( DUMMY_WRAPPER (initial_argument, arg2, arg3)))

在上面的编译过程中,我看到编译器/预处理器的预期输出:

#pragma message: ( initial_argument { {initial_argument, arg2} , {initial_argument, arg3} }; 2)

但是,当我尝试用参数定义一个宏并将 that 传递给 DUMMY_WRAPPER 时,我得到一个“额外的”空参数。示例:

#define ARGS initial_argument, arg2, arg3
#pragma message STRINGIZE( ( DUMMY_WRAPPER (ARGS) ))

编译器输出(与正确输出比较):

#pragma message: ( initial_argument { {initial_argument, arg2} , {initial_argument, arg3} , {initial_argument, } }; 3 )

我如何去掉这个额外的参数?

完整代码(带解释)

Nota Bene:我承认这可能是非常糟糕的宏滥用,并且有更好的方法使用 C++ 进行元编程,但我只是想让它快速工作。

我使用 GCC/G++ 进行编译。

这是工作代码 + 编译器输出,供您轻松在线测试/试验:https://godbolt.org/z/wGFbrK

#define COMMA() ,

// routines for stringizing macros, similar to BOOST_PP_STRINGIZE
#define STR1(x) #x
#define STRINGIZE(x) STR1(x)

// routine & subroutines for argument counting
#define NARG(...) \
NARG_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define ARG_N(_1,_2,_3,_4,_5, N, ... ) N
#define NARG_(...) ARG_N(__VA_ARGS__)

// routines for "looped" macro expansion, for processing lists of macro arguments
#define LOOP_1(M, C, D, x) M(C, x)
#define LOOP_2(M, C, D, x, ...) M(C, x) D() \
LOOP_1(M, C, D, __VA_ARGS__)
#define LOOP_3(M, C, D, x, ...) M(C, x) D() \
LOOP_2(M, C, D, __VA_ARGS__)
#define LOOP_4(M, C, D, x, ...) M(C, x) D() \
LOOP_3(M, C, D, __VA_ARGS__)
#define LOOP_5(M, C, D, x, ...) M(C, x) D() \
LOOP_4(M, C, D, __VA_ARGS__)

// routine for concatenating things, used here to expand loop routine names, i.e. LOOP_ + 3 => LOOP_3
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__

// **** TOP-LEVEL ****
// (code using above routines to demonstrate the problem)

// lists the first argument, i.e. C in the loop, and some other argument
#define LIST_FIELD(arg1, a, ... ) {arg1, a}

#define DUMMY_WRAPPER(arg1, ...) DUMMY( arg1, __VA_ARGS__)

#define DUMMY( arg1, ...) \
DUMMY_2(arg1, NARG(__VA_ARGS__), __VA_ARGS__)

#define DUMMY_2( arg1, field_count, ...) \
DUMMY_3(arg1, CAT(LOOP_, field_count), __VA_ARGS__) \
field_count

#define DUMMY_3( arg1, loop, ...) \
arg1 { \
loop(LIST_FIELD, arg1, COMMA, __VA_ARGS__) \
};

#pragma message STRINGIZE( ( DUMMY_WRAPPER (initial_argument, arg2, arg3)))
#define ARGS initial_argument, arg2, arg3
#pragma message STRINGIZE( ( DUMMY_WRAPPER (ARGS) ))

(一些)可能相关的研究(不确定)

https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/

不确定这是否可以解释这里的事情,但是,直觉上我认为不能......

最佳答案

当你的编译器看到这个:DUMMY_WRAPPER (ARGS)

它将使用 ARGS 作为 DUMMY_WRAPPER 的第一个参数,即使 ARGS 的扩展包含逗号。

这可以通过从 DUMMY_WRAPPER 中删除第一个参数并仅使用 __VA_ARGS__ 来解决:

#define DUMMY_WRAPPER(...) DUMMY(__VA_ARGS__)

OR 通过将 DUMMY_WRAPPER 包装在另一个宏中:

#define DUMMY_WRAPPER_2(...) DUMMY_WRAPPER(__VA_ARGS__)

事实上,您的代码根本不应该编译,因为 ... 宏参数必须接收至少一个参数(可以为空)。 DUMMY_WRAPPER(x) 无效,但 DUMMY_WRAPPER(x,)DUMMY_WRAPPER(x,y) 正常。 (这在 C++20 中可能已更改,我不确定。)

如果您添加 -pedantic-errors,GCC 和 Clang 将拒绝编译代码。


我还建议您使用不同的循环方法。您正在使用的那个要求您生成 O(n) 代码来处理 n 列表元素。

如果稍微更改一下宏语法,则可以用 O(1) 代码做同样的事情:

#include <iostream>

#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) #__VA_ARGS__

#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_end

#define BODY(x) [x]
#define BODY_a(x) BODY(x) BODY_b
#define BODY_b(x) BODY(x) BODY_a
#define BODY_a_end
#define BODY_b_end

#define LOOP(seq) END(BODY_a seq)

int main()
{
// Prints `[1] [2] [3]`
std::cout << STR(LOOP( (1)(2)(3) )) << '\n';
}

在这里,LOOP 可以处理任意数量的元素,而不需要样板宏。

但它不太灵活,因为您不能从外部向循环体传递任何信息。但它应该足以满足您的需求。

这是一个在元素之间插入逗号的版本:

#include <iostream>

#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) #__VA_ARGS__

#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_end

#define BODY(x) [x]
#define BODY_0(x) BODY(x) BODY_a
#define BODY_a(x) , BODY(x) BODY_b
#define BODY_b(x) , BODY(x) BODY_a
#define BODY_0_end
#define BODY_a_end
#define BODY_b_end

#define LOOP(seq) END(BODY_0 seq)

int main()
{
// Prints `[1] , [2] , [3]`
std::cout << STR(LOOP( (1)(2)(3) )) << '\n';
}

关于c++ - 将宏传递给另一个宏而不是直接传递东西时出现不需要的额外 "empty"参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59616208/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com