首页 > 解决方案 > 扩展 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);
                                      

标签: c++macrosvariadic-templatesc++20variadic-macros

解决方案


递归宏是不可能的:

如果在替换列表的扫描过程中找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,它不会被替换。这些未替换的宏名称预处理标记不再可用于进一步替换,即使它们稍后在该宏名称预处理标记将被替换的上下文中进行(重新)检查。

但是有一些解决方法可以进行多次评估来模拟递归调用,达到一定的限制。

#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__))

演示


推荐阅读