博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C preprocessor macro specialisation based on an argument
阅读量:7004 次
发布时间:2019-06-27

本文共 8134 字,大约阅读时间需要 27 分钟。

http://stackoverflow.com/questions/11632219/c-preprocessor-macro-specialisation-based-on-an-argument

Tuns out it is possible. This anwser is based on Pauls macros, but much simpler and does not need definition for each user.

#define CAT(a,...)   PRIMITIVE_CAT(a, __VA_ARGS__)#define PRIMITIVE_CAT(a,...) a ## __VA_ARGS__#define IIF(c) PRIMITIVE_CAT(IIF_, c)#define IIF_0(t,...) __VA_ARGS__#define IIF_1(t,...) t#define PROBE(x) x,1

Now, because of the MSVC bug I had to modify CHECK macro a bit.

#define MSVC_VA_ARGS_WORKAROUND(define, args) define args#define CHECK(...) MSVC_VA_ARGS_WORKAROUND(CHECK_N,(__VA_ARGS__,0))#define CHECK_N(x, n,...) n

Instead of defining CURRENT_USER I switched to following macros.

#define ENABLE_USER_gwiazdorrr ()  // gwiazdorrr is now enabled#define ENABLE_USER_foo ()      // foo is also enabled// #define ENABLE_USER_bar ()     // bar is NOT enabled

It actually gives more flexibility, because one can enable multiple user at the same time.

The parenthesis is required. The macros below actually detect,
whether ENABLE_USER_<user> is expanded into parenthesis or not.

#define USER_ENABLED_PROBE(user)        USER_ENABLED_PROBE_PROXY( ENABLE_USER_##user )    // concatenate prefix with user name#define USER_ENABLED_PROBE_PROXY(...)    USER_ENABLED_PROBE_PRIMIVIE(__VA_ARGS__)       // expand arguments#define USER_ENABLED_PROBE_PRIMIVIE(x)   USER_ENABLED_PROBE_COMBINE_##x             // merge#define USER_ENABLED_PROBE_COMBINE_(...)  PROBE(~)                          // if merge successful, expand to probe

USER_ENABLED_PROBE(gwiazdorrr)    // expands to ~, 1

USER_ENABLED_PROBE(bar)        // expands to USER_ENABLED_PROBE_COMBINE_bar

From now it is a childs play:

#define IS_USER_ENABLED(user)     CHECK( USER_ENABLED_PROBE(user) )

IS_USER_ENABLED(gwiazdorrr)      // expands to 1

IS_USER_ENABLED(bar)          // expands to 0

Having this macro and IIF (thanks Paul!)
I decided to implement the optimisation macro mentioned in the original question:

#define TURN_OPTIMISATION_OFF(user) IIF( IS_USER_ENABLED(user) ) ( __pragma optimize("", off), /* nothing */ )

TURN_OPTIMISATION_OFF(gwiazdorrr)  // expands into __pragma optimize("", off)

TURN_OPTIMISATION_OFF(foo)      // expands into __pragma optimize("", off)
TURN_OPTIMISATION_OFF(bar)      // nothing emitted

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__#define IIF(c) PRIMITIVE_CAT(IIF_, c)#define IIF_0(t, ...) __VA_ARGS__#define IIF_1(t, ...) t#define PROBE(x) x, 1 #define CHECK(...) CHECK_N(__VA_ARGS__, 0)#define CHECK_N(x, n, ...) n#define ENABLE_USER_gwiazdorrr () // gwiazdorrr is now enabled#define ENABLE_USER_foo ()        // foo is also enabled// #define ENABLE_USER_bar ()     // bar is NOT enabled#define USER_ENABLED_PROBE(user)            USER_ENABLED_PROBE_PROXY( ENABLE_USER_##user ) // concatenate prefix with user name#define USER_ENABLED_PROBE_PROXY(...)       USER_ENABLED_PROBE_PRIMIVIE(__VA_ARGS__)       // expand arguments#define USER_ENABLED_PROBE_PRIMIVIE(x)      USER_ENABLED_PROBE_COMBINE_ x                  // merge#define USER_ENABLED_PROBE_COMBINE_(...)    PROBE(~)                                       // if merge successful, expand to probe#define IS_USER_ENABLED(user) CHECK(USER_ENABLED_PROBE(user))#define TURN_OPTIMISATION_OFF(user) IIF( IS_USER_ENABLED(user) ) \    (\        _Pragma ("GCC optimize \"0\""),\        /* nothing */ \    )TURN_OPTIMISATION_OFF(gwiazdorrr) // expands into __pragma optimize("", off)TURN_OPTIMISATION_OFF(foo)        // expands into __pragma optimize("", off)TURN_OPTIMISATION_OFF(bar)        // nothing emittedint main(){    return 0;}

 

Well first, you can do pattern matching with the preprocessor using the ##. This is how an IIF macro could be defined:

#define IIF(cond) IIF_ ## cond#define IIF_0(t, f) f#define IIF_1(t, f) t

However there is one problem with this approach. A subtle side effect of the ##operator is that it inhibits expansion. Heres an example:

#define A() 1//This correctly expands to trueIIF(1)(true, false) // This will however expand to IIF_A()(true, false)// This is because A() doesn't expand to 1,// because its inhibited by the ## operatorIIF(A())(true, false)

The way to work around this is to use another indirection. Sense this is commonly done we can write a macro called CAT that will concatenate without inhibition.

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

So now we can write the IIF macro:

#define IIF(c) PRIMITIVE_CAT(IIF_, c)#define IIF_0(t, ...) __VA_ARGS__#define IIF_1(t, ...) t#define A() 1//This correctly expands to trueIIF(1)(true, false) // And this will also now correctly expand to trueIIF(A())(true, false)

 

With pattern matching we can define other operations, such as COMPL which takes the complement:

// A complement operator#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)#define COMPL_0 1#define COMPL_1 0// An and operator#define BITAND(x) PRIMITIVE_CAT(BITAND_, x)#define BITAND_0(y) 0#define BITAND_1(y) y

 

Next, detection techniques can be used to detect if the parameter is a certain value or if it is parenthesis. It relies on vardiac arguments expanding to different number of parameters. At the core of detection is a CHECK macro with aPROBE macro like this:

#define CHECK_N(x, n, ...) n#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)#define PROBE(x) x, 1,

This is very simple. When the probe is given to the CHECK macro like this:

CHECK(PROBE(~)) // Expands to 1

But if we give it a single token:

CHECK(xxx) // Expands to 0

So with this, we can create some detection macros. For instance, if we want to detect for parenthesis:

#define IS_PAREN(x)        CHECK(IS_PAREN_PROBE x)#define IS_PAREN_PROBE(...)   PROBE(~)IS_PAREN(())            // Expands to 1IS_PAREN(xxx)           // Expands to 0

 

Next, we need to do a comparison of two tokens, we can rely on the fact that macros don't expand recursively.

We force the macro to expand recursively inside of the other macro.
If the two tokens are the same then the it will be expanding the macros recursively,
which we will detect by trying detect if they expanded to parenthesis or not, here is the COMPARE macro:

#define COMPARE(a, b) PRIMITIVE_COMPARE(a, b)#define PRIMITIVE_COMPARE(a, b) \    IIF( BITAND ( IS_PAREN(COMPARE_##a(())) ) ( IS_PAREN(COMPARE_##b(())) ) ) \       ( COMPL(IS_PAREN( COMPARE_##a( COMPARE_##b )(()))), 0 )

Each token you want to compare you would define like this:

#define CURRENT_USER john_smith#define COMPARE_john_smith(x) x#define COMPARE_user_name(x) xCOMPARE(user_name, john_smith ) : IIF( 1 ) ( 0, 0 )                                             *1) IIF( BITAND ( IS_PAREN( COMPARE_##a( () ) ) ) ( IS_PAREN( COMPARE_##b( () ) ) ) )   IS_PAREN( COMPARE_##a( () ) ) --> IS_PAREN( COMPARE_user_name( () ) ) --> IS_PAREN( () ) --> 1   IS_PAREN( COMPARE_##b( () ) ) --> IS_PAREN( COMPARE_john_smith( () ) ) --> IS_PAREN( () ) --> 12) ( COMPL( IS_PAREN( COMPARE_##a( COMPARE_##b )( () ) ) ), 0 )   ( COMPL( IS_PAREN( COMPARE_user_name( COMPARE_john_smith )( () ) ) ), 0 )   ( COMPL( IS_PAREN( COMPARE_john_smith( () ) ) ), 0 )   ( COMPL( IS_PAREN( () ) ), 0 )   ( COMPL( 1 ), 0 )   ( 0, 0 )COMPARE(john_smith, john_smith ) : IIF( 1 ) ( 1, 0 )                                              *1) IIF( BITAND ( IS_PAREN( COMPARE_##a( () ) ) ) ( IS_PAREN( COMPARE_##b( () ) ) ) )   IS_PAREN( COMPARE_##a( () ) ) --> IS_PAREN( COMPARE_john_smith( () ) ) --> IS_PAREN( () ) --> 1   IS_PAREN( COMPARE_##b( () ) ) --> IS_PAREN( COMPARE_john_smith( () ) ) --> IS_PAREN( () ) --> 12) ( COMPL( IS_PAREN( COMPARE_##a( COMPARE_##b )( () ) ) ), 0 )   ( COMPL( IS_PAREN( COMPARE_john_smith( COMPARE_john_smith )( () ) ) ), 0 )   ( COMPL( 0 ), 0 )    ( 1, 0 )// Detects if its the current user : COMPARE(user, john_smith )#define IS_CURRENT_USER(user) COMPARE(user, CURRENT_USER)// Your macro#define MACRO_CURRENT_USER(user) 1#define MACRO_OTHER_USER(user) 0#define MACRO( user ) \IIF( IS_CURRENT_USER(user) ) ( MACRO_CURRENT_USER, MACRO_OTHER_USER ) ( user )MACRO( user_name ) --> MACRO_OTHER_USER --> 0MACRO( john_smith ) -> MACRO_CURRENT_USER --> 1

 

转载地址:http://qcutl.baihongyu.com/

你可能感兴趣的文章
Spring-MVC:应用上下文webApplicationContext
查看>>
bzoj 2038 小Z的袜子
查看>>
CMake学习之路
查看>>
Js让光标停在输入框input框最后面
查看>>
隐藏的最大整数
查看>>
CSS 三栏自适应布局
查看>>
[SharePoint 2010]关于基于声明(Claims)的用户认证模式
查看>>
python开发函数进阶:装饰器
查看>>
Python中的数据结构 --- 集合(set)
查看>>
自动驾驶系统方向
查看>>
HDU 4576 Robot
查看>>
Hibernate实体关系映射(OneToMany单边)——完整实例
查看>>
NSBundle 的理解和 mainBundle 类方法的详解
查看>>
Android——POST传输(一)
查看>>
模块与包
查看>>
Augmenting Path Algorithm : 一般图最大匹配
查看>>
基于HTML5树组件延迟加载技术实现
查看>>
error LNK2026: 模块对于 SAFESEH 映像是不安全的
查看>>
js工具库---Lodash
查看>>
Delphi总结使用TStrings的一些技巧
查看>>