假设我有一个宏:
#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
。
答案 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
引入的。
然后,建议的宏如下。 这对您也有用。
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__))