【问题标题】:How can I guarantee full macro expansion of a parameter before paste?如何保证粘贴前参数的完整宏扩展?
【发布时间】:2010-07-11 04:49:51
【问题描述】:

我有一个通用宏:

#define mSwitch( Root, Case )  Root##_Case_##Case

#define mSpecialDisplay( what, Val )  mSwitch(mSpecialDisplay,what)(Val)
#define mSpecialDisplay_Case_Int(Val)    ...do stuff
#define mSpecialDisplay_Case_Float(Val)  ...do stuff
...more special cases

如何保证变量Case 在粘贴到mSwitch 之前完全展开?

如果 mSwitch 被传递一个文字值,它工作正常,但如果有多层间接或中间操作,mSwitch 最终会在它们完全展开之前粘贴其中一层。

我正在使用MSVC 2005

有没有一种简单的方法可以确保参数在粘贴完成之前完全展开?

谢谢


好吧,举个例子也许并不难:

  #define mMDebugInfo( ... ) mMDebugExp( mMDebugInfo_( 0, __VA_ARGS__ ) )

  #define mMDebugInfo_( C, ... ) mMAritize( mMSwitch( mMDebugInfo, mMMetaTrait( Detect, __VA_ARGS__ ) ), (C, __VA_ARGS__) )

  #define mMDebugInfoRep( C, ... ) mMXP##C( mMDebugInfo_ )mMXP##C((mMIInc(C),__VA_ARGS__)) //(mMExpDo(mMGlue( mM, C)##DebugInfo_(mMIInc(C),__VA_ARGS__))

  #define mMDebugInfo1( C, ... ) mMAritize( mMSwitch( mMDebugInfo, mMMetaTrait( Detect, __VA_ARGS__ ) ), (mMIInc(C), __VA_ARGS__) )

  #define mMDebugInfo_Case_Nil(...) [Nil]

  #define mMDebugInfo_Case_CntArgs(C,I,...) 
mMDebugInfoRep(C,I),mMDebugInfoRep(C,__VA_ARGS__)
  #define mMDebugInfo_Case_PrnNull(C,I) [()]

  #define mMDebugInfo_Case_Prn(C,I)   ( mMDebugInfoRep(C,mMDPrn(I)) )

  #define mMDebugInfo_Case_ActFn(C,I) mMAritize( mMDebugInfo_Case_Fn, (C, I, mMTrait_Fn_mM##I) )

  #define mMDebugInfo_Case_PassFn(C,I) mMAritize( mMDebugInfo_Case_Fn, (C, mMTrait_Fn_mM##I) )

  #define mMDebugInfo_Case_Fn( C,Name, Reg, ArgCnt, PArgs ) [Name:ArgCnt]( mMAritize( mMSwitch( mMDebugInfo_Case_Fn, ArgCnt ), (C, mMDPrn( PArgs ) )) )

  #define mMDebugInfo_Case_Fn_Case_V(C, _1, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, __VA_ARGS__)

  #define mMDebugInfo_Case_Fn_Case_0(...) [Nil]

  #define mMDebugInfo_Case_Fn_Case_1(C, _1, ...) mMDebugInfoRep(C, _1)

  #define mMDebugInfo_Case_Fn_Case_2(C, _1, _2, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, _2)

  #define mMDebugInfo_Case_Fn_Case_3(C, _1, _2, _3, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, _2), mMDebugInfoRep(C, _3)  

  #define mMDebugInfo_Case_Fn_Case_4(C, _1, _2, _3, _4, ...) mMDebugInfoRep(C, _1), mMDebugInfoRep(C, _2), mMDebugInfoRep(C, _3), mMDebugInfoRep(C, _4)

  #define mMDebugInfo_Case_Int(C,I)   [Num:I]

  #define mMDebugInfo_Case_Digit(C,I) [Dig:I] 

  #define mMDebugInfo_Case_Bool(C,I)  [Bin:I]

  #define mMDebugInfo_Case_CCode(C,I) [CCd:I]

  #define mMDebugInfo_Case_UToken(C,I) [UT:I]

这是在递归解析嵌套表达式时没有问题的调试代码,例如:

DebugInfo( BInt( BNot( IAdd(4,BNot(IAdd(6,7)) ) ) ) ); 
"

产生:

"[BInt:1]( [BNot:1]( [IAdd:2]( [Dig:4], [BNot:1]( [IAdd:2]( [Dig:6], [Dig:7] ) ) ) ) )"

示例表达式中的宏函数处于非活动形式。当我激活表单时,问题就出现了 - 各个参数的解析链可能会变得任意长,并且在使用之前它们没有得到完全解决。

【问题讨论】:

标签: c++ macros c-preprocessor


【解决方案1】:

这是通常的成语:

#define mSwitch(Root, Case) mSwitch_(Root, Case)
#define mSwitch_(Root, Case) Root##_Case_##Case

C 预处理器宏的所有参数都在宏本身展开之前完全展开,除非### 运算符应用于它们;然后他们没有扩大。因此,要在 ## 之前获得完全扩展,您可以通过不使用 ## 的包装宏传递参数。

【讨论】:

  • 不相关,出于病态的好奇心,人们在哪里学习写“function( argument, argument )”——即括号内有空格?我经常看到它,它让我的审美在痛苦中挣扎。
  • 谢谢,我试过了。我认为问题正在扩大,因为中间操作可能正在应用他们自己的粘贴。如果我创建一个任意长的列表: #define mSwitch( A, B ) mSwitch1(A,B) #define mSwitch1( A, B ) mSwitch2(A,B) ... #define mSwitchN( A, B ) Root ##_Case_##Case 它最终会起作用。还有什么可以尝试的吗?
  • @Zack,它在某些地方是必需的风格(比如我工作的地方)。你会习惯的。
  • 没有其他方法可以控制是否发生这种情况,但是无论发生什么其他情况,一层包装器应该就足够了。我需要查看一个完整的独立示例,以提供更具体的建议。 (顺便说一句,您很可能遇到了 MSVC 错误。您尝试过 2008 版吗?还是 gcc?)
  • @JS Bangs,我知道很多地方在他们需要的风格指南中都有这个(谢天谢地不是我工作的地方)但是它在哪里 从?谁发明的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 1970-01-01
  • 2020-11-22
  • 2022-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多