问题描述
我问了一个问题: Why you should never use function calls in Angular template expressions
#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,c,d) X(a),X(c),X(d)
#define APPLYX5(a,d,e) X(a),X(d),X(e)
#define APPLYX6(a,e,f) X(a),X(e),X(f)
#define APPLYX7(a,f,g) \
X(a),X(f),X(g)
#define APPLYX8(a,g,h) \
X(a),X(g),X(h)
#define APPLYX9(a,h,i) \
X(a),X(h),X(i)
#define APPLYX10(a,i,j) \
X(a),X(i),X(j)
#define APPLYX11(a,j,k) \
X(a),X(j),X(k)
#define APPLYX12(a,k,l) \
X(a),X(k),X(l)
#define APPLYX13(a,l,m) \
X(a),X(l),X(m)
#define APPLYX14(a,m,n) \
X(a),X(m),X(n)
#define APPLYX15(a,n,o) \
X(a),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);
}
c++ macro expansion(__VA_ARGS__ item name and value)
在传统的预处理器中,如果一个宏将它的一个参数转发给另一个依赖的宏,那么该参数在插入时不会被“解包”。通常这种优化不会被注意到,但它可能会导致异常行为:
// 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 中使用了一些最新的宏功能,例如 macro unpacked 或 VA_OPT。我能否在不使用 PP_ARG_N 等复杂预定义的情况下简化传统实现并真正支持任意数量的参数?
嗯,是这样的:
#define NEW_IMPL(x1,...) std::make_pair(#x1,&x1),NEW_IMPL(__VA_ARGS__) // head,rest of the arguments,like variadic templates
NEW_IMPL(a,e);
解决方法
递归宏是不可能的:
如果在替换列表的这次扫描中找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会替换它。这些未替换的宏名称预处理标记不再可用于进一步替换,即使稍后在宏名称预处理标记将被替换的上下文中(重新)检查它们。
但是有一些解决方法可以让 several evaluations to mimic recursive call 达到一定的限制。
#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__))