提取__VA_ARGS__的第一个参数

时间:2018-12-03 16:23:27

标签: c++ c++17

假设我有一个宏:

#define FOO(a, ...) if (a) foo(a, ## __VA_ARGS__)

效果很好:

  • FOO(a)将转换为if (a) foo(a)
  • FOO(a, <some_parameters>)将转换为if (a) foo(a, <some_parameters>)

是否可以修改此宏,以便仅将__VA_ARGS__的第一个参数(如果存在)传递给foo?所以,我需要:

  • FOO(a)转换为if (a) foo(a)
  • FOO(a, b, <some_parameters>)转换为if (a) foo(a, b)

我尝试用与BOOST_PP_VARIADIC_SIZE相同的思想来解决此问题,但事实证明此宏为1返回了BOOST_PP_VARIADIC_SIZE()(空参数),这是不希望的(我期望0)。

请注意,我需要一个解决方案,其中仅在b<some_parameters>时才评估bool(a)true

2 个答案:

答案 0 :(得分:2)

我提出了一个带有通用lambda的可变参数宏作为解决方案。 要点如下:

  • 很难将Select A.Type ,A.Description ,C.* From YourTable A Cross Apply (values ( replace( replace( replace( replace(A.Description,',',' ') ,' ',' ') ,'Model ','Model') ,'S/N ','S/N') ) )B(CleanString) Cross Apply ( Select Quantity = IsNull(left(max(case when RetSeq=1 then RetVal end),NullIf(patindex('%[^0-9]%',max(case when RetSeq=1 then RetVal end)) -1,0)),1) ,Name = substring(max(case when RetSeq=1 then RetVal end),patindex('%[^0-9]%',max(case when RetSeq=1 then RetVal end)),charindex(' ',max(case when RetSeq=1 then RetVal end)+' ')-1) ,Weight = IIF(A.Type=2,null,try_convert(decimal(5,1),replace(max(case when RetVal like '%PW' then RetVal end),'PW',''))) ,Purity = try_convert(smallint ,replace(max(case when RetVal like '%K' then RetVal end),'K','')) ,Brand = IIF(A.Type=1,null,max(case when RetSeq=2 then RetVal end)) ,Model = replace(max(case when RetVal Like 'Model[0-9,A-Z]%' then RetVal end),'Model','') ,SerialNum = replace(max(case when RetVal Like 'S/N[0-9,A-Z]%' then RetVal end),'S/N','') From ( Select RetSeq = row_number() over (Order By (Select null)) ,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)'))) From (Select x = Cast('<x>' + replace((Select replace(CleanString,' ','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A Cross Apply x.nodes('x') AS B(i) ) B1 ) C a都传递给lambda作为宏中的传递参数,因为__VA_ARGS__为空

    __VA_ARGS__

    成为

    [](){...}(a, __VA_ARGS__)
    

    ,此[](){...}(a,) 导致编译错误。 因此,我们将,的第一个参数和第二个参数分别分为捕获的参数和传递的参数,如下所示。 然后,即使FOO为空,我们也可以在宏中使用通用lambda。

    __VA_ARGS__
  • [a](){...}(__VA_ARGS__) 的大小可以在编译时评估为__VA_ARGS__。然后,我们可以使用constexpr auto N来分隔函数调用。

  • 我们还可以将 if语句与初始化程序一起应用,该语句是C ++ 17中针对if constexpr引入的。

然后,建议的宏如下。 这对您也有用。

DEMO

if(a)

答案 1 :(得分:1)

基于此answer,我可以解决问题:

#define PRIVATE_CONCAT(a, b) a ## b

#define CONCAT(a, b) PRIVATE_CONCAT(a, b)

#define GET_100TH( \
    _01, _02, _03, _04, _05, _06, _07, _08, _09, _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, _64, _65, _66, _67, _68, _69, _70,  \
    _71, _72, _73, _74, _75, _76, _77, _78, _79, _80,  \
    _81, _82, _83, _84, _85, _86, _87, _88, _89, _90,  \
    _91, _92, _93, _94, _95, _96, _97, _98, _99, PAR,  \
    ...) PAR

#define HAS_PARAMETER(...) GET_100TH(placeholder, ##__VA_ARGS__, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
        1, 1, 1, 1, 1, 1, 1, 1, 0)

#define FIRST_PARAMETER_WITH_PREPENDED_COMMA0(...)
#define FIRST_PARAMETER_WITH_PREPENDED_COMMA1(a, ...) , a

#define FIRST_PARAMETER_WITH_PREPENDED_COMMA(...) CONCAT(FIRST_PARAMETER_WITH_PREPENDED_COMMA, HAS_PARAMETER(__VA_ARGS__))(__VA_ARGS__)

#define FOO(a, ...) if (a) foo(a FIRST_PARAMETER_WITH_PREPENDED_COMMA(__VA_ARGS__))
相关问题