花费 PPNARG 宏的技巧或新方法

问题描述

我问了一个问题: 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)

demo

在传统的预处理器中,如果一个宏将它的一个参数转发给另一个依赖的宏,那么该参数在插入时不会被“解包”。通常这种优化不会被注意到,但它可能会导致异常行为:

// 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 中使用了一些最新的宏功能,例如 ma​​cro unpackedVA_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__))

Demo

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...