c++ - 扩展 PPNARG 宏的技巧或新方法
问题描述
我问了一个问题: c++宏扩展(__VA_ARGS__项名称和值)
#include <iostream>
#include <memory>
#include <vector>
#include <functional>
#define PP_NARG(...) PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
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,0
/* need extra level to force extra eval */
#define Paste(a,b) a ## b
#define XPASTE(a,b) Paste(a,b)
/* APPLYXn variadic X-Macro by M Joshua Ryan */
/* Free for all uses. Don't be a jerk. */
/* I got bored after typing 15 of these. */
/* You could keep going upto 64 (PPNARG's limit). */
#define APPLYX1(a) X(a)
#define APPLYX2(a,b) X(a), X(b)
#define APPLYX3(a,b,c) X(a), X(b), X(c)
#define APPLYX4(a,b,c,d) X(a), X(b), X(c), X(d)
#define APPLYX5(a,b,c,d,e) X(a), X(b), X(c), X(d), X(e)
#define APPLYX6(a,b,c,d,e,f) X(a), X(b), X(c), X(d), X(e), X(f)
#define APPLYX7(a,b,c,d,e,f,g) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g)
#define APPLYX8(a,b,c,d,e,f,g,h) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h)
#define APPLYX9(a,b,c,d,e,f,g,h,i) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i)
#define APPLYX10(a,b,c,d,e,f,g,h,i,j) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i), X(j)
#define APPLYX11(a,b,c,d,e,f,g,h,i,j,k) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i), X(j), X(k)
#define APPLYX12(a,b,c,d,e,f,g,h,i,j,k,l) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i), X(j), X(k), X(l)
#define APPLYX13(a,b,c,d,e,f,g,h,i,j,k,l,m) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i), X(j), X(k), X(l), X(m)
#define APPLYX14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i), X(j), X(k), X(l), X(m), X(n)
#define APPLYX15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \
X(a), X(b), X(c), X(d), X(e), X(f), X(g), X(h), X(i), X(j), X(k), X(l), X(m), X(n), X(o)
#define APPLYX_(M, ...) M(__VA_ARGS__)
#define APPLYXn(...) APPLYX_(XPASTE(APPLYX, PP_NARG(__VA_ARGS__)), __VA_ARGS__)
#define X(a) std::make_pair(#a, a)
#define FAKE_MACRO(...) fake_fold(APPLYXn(__VA_ARGS__))
template <typename ... Pairs>
void fake_fold(const Pairs&... ps)
{
((std::cout << ps.first << ": " << ps.second << std::endl), ...);
}
int main()
{
int var1 = 42;
std::string var2 = "toto";
double var3 = 5.1;
FAKE_MACRO(var1, var2, var3);
}
在传统的预处理器中,如果一个宏将它的一个参数转发给另一个从属宏,那么该参数在插入时不会被“解包”。通常这种优化不会被注意到,但它可能会导致异常行为:
// Create a string out of the first argument, and the rest of the arguments.
#define TWO_STRINGS( first, ... ) #first, #__VA_ARGS__
#define A( ... ) TWO_STRINGS(__VA_ARGS__)
const char* c[2] = { A(1, 2) };
// Conforming preprocessor results:
// const char c[2] = { "1", "2" };
// Traditional preprocessor results, all arguments are in the first string:
// const char c[2] = { "1, 2", };
问题:如果我在 C++20 中 使用一些最新的宏功能,例如宏解包或VA_OPT 。我可以在不使用像PP_ARG_N 之类的复杂预定义的情况下简化传统工具并真的支持任意数量的参数吗?
emm,是这样的:
#define NEW_IMPL(x1, ...) std::make_pair(#x1, &x1), NEW_IMPL(__VA_ARGS__) // head, rest of the arguments, like variadic templates
NEW_IMPL(a, b, c, d, e);
解决方案
递归宏是不可能的:
如果在替换列表的扫描过程中找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,它不会被替换。这些未替换的宏名称预处理标记不再可用于进一步替换,即使它们稍后在该宏名称预处理标记将被替换的上下文中进行(重新)检查。
但是有一些解决方法可以进行多次评估来模拟递归调用,达到一定的限制。
#define EMPTY(...)
#define DEFER(...) __VA_ARGS__ EMPTY()
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
#define FOR_EACH_ID() FOR_EACH
#define FOR_EACH(F, X, ...) F(X) __VA_OPT__(, DEFER(FOR_EACH_ID)()(F, __VA_ARGS__))
#define F(X) std::make_pair(#X, X)
#define NEW_IMPL(...) EVAL(FOR_EACH(F, __VA_ARGS__))
推荐阅读
- bash - 我正在准备用组名替换 UNIX 中的组号
- c# - ASp.net core IActionResult csv编码问题
- javascript - 如何在延迟的无限循环中使用承诺?
- here-api - 从“Geocoding and Search API v7 service”获取“Places (Search) API”的“Image Media Type”等价物
- nosql - 当收缩 litedb 文件时,应用程序无法找到索引
。_ID。我该如何解决? - graph - Gremlin 查询:如何 AND & OR 关系?
- python - 如何在不影响 0 权重神经元的情况下计算 FLOPs 和 Params?
- c++ - C++ 异常框架是否需要内核支持?
- typescript - Type Guard Typescript 未正确推断函数剩余参数
- python - 如何限制 jsonschema 中未声明的添加字段