使用boost预处理器序列时避免扩展宏

时间:2017-11-22 13:03:28

标签: c++ boost preprocessor boost-preprocessor

我正在尝试将操作系统和编译器名称作为C ++中的字符串。虽然有很多问题,但我没有找到明确的答案。所以我尝试使用Boost.Predef 1.55来定义BOOST_OS_<OS>BOOST_OS_<OS>_NAME类型的宏。

因此,对于每个OS提升支持,可以简单地执行if(BOOST_OS_<OS>) return BOOST_OS_<OS>_NAME;。对于COMP而不是OS的编译器也是如此。为了避免重复,我想使用Boost.Preprocessor并将它们全部放在循环中。

我想出的是:

#define MAKE_STMT_I2(PREFIX) if(PREFIX) return PREFIX ## _NAME;
#define MAKE_STMT_I(type, curName) MAKE_STMT_I2(BOOST_ ## type ## _ ## curName)
#define MAKE_STMT(s, type, curName) MAKE_STMT_I(type, curName)
#define OS_LIST (AIX)(AMIGAOS)(ANDROID)(BEOS)(BSD)(CYGWIN)(HPUX)(IRIX)(LINUX)(MACOS)(OS400)(QNX)(SOLARIS)(UNIX)(SVR4)(VMS)(WINDOWS)(BSDI)(DRAGONFLY)(BSD_FREE)(BSD_NET)(BSD_OPEN)

    BOOST_PP_SEQ_FOR_EACH(MAKE_STMT, OS, OS_LIST)

但是我遇到的问题很快就会扩展到值。例如。 VMS已经定义了一个名为VMS的宏,然后在OS_LIST中替换它。即使像#define OS_LIST (##AIX##)(##AMIGAOS##)(...这样的事情也无济于事,因为它似乎在以后的升级中得到了扩展。

如何完全避免序列中的扩展?

2 个答案:

答案 0 :(得分:2)

由于您依赖未定义的令牌VMS,因此快速解决方案很简单#undef VMS。显然,为了避免破坏依赖于该宏的代码,您应该将Boost PP代码放在自己的.cpp文件中。

答案 1 :(得分:2)

如何完全避免序列中的扩展?

你做不到。将高级数据结构作为参数传递给宏必然涉及评估数据结构。

你可以避免这个问题,并且仍然基本上以三种方式使用boost宏:

1。在调用之前解决问题宏

这基本上是MSalters推荐的。

这个想法是,如果没有定义VMS,它的评估就不会扩展它。

在这里,你冒着VMS未定义的风险,这可能会产生可怕的后果,所以你必须减轻它(MSalters对此有所了解)。

2。从不同的数据构建高级宏

例如,

2可能会使用:

#define OS_LIST (S_AIX)(S_BEOS)(S_VMS)

...并要求您更改MAKE_STMT宏复合体;例如,这个:

#define MAKE_STMT_I2(PREFIX) if(PREFIX) return PREFIX ## _NAME;
#define MAKE_STMT_I(curName) MAKE_STMT_I2(BOOST_O ## curName)
#define MAKE_STMT(s, type, curName) MAKE_STMT_I(curName)
#define OS_LIST (S_AIX)(S_AMIGAOS)(S_ANDROID)(S_BEOS)(S_BSD)(S_CYGWIN)(S_HPUX)(S_IRIX)(S_LINUX)(S_MACOS)(S_OS400)(S_QNX)(S_SOLARIS)(S_UNIX)(S_SVR4)(S_VMS)(S_WINDOWS)(S_BSDI)(S_DRAGONFLY)(S_BSD_FREE)(S_BSD_NET)(S_BSD_OPEN)

(注意:这里我忽略了类型;无需将OS作为数据传递给迭代序列。

这里的想法是找到BOOST_OS_FOOBOOST_OS_FOO_NAME的不同共享部分来放入您的数据,这样您的数据就不会包含您定义的宏。

在这里,您可能会在某个更高级别定义S_FOO的风险使您陷入困境。您可以通过查找要在数据中使用的其他部分来缓解此问题。

3。构建包装器标识符

这最容易通过示例来定义:

#define OS_LIST (AIX)(BEOS)(8VMS)
#define BOOST_OS_8VMS BOOST_OS_VMS
#define BOOST_OS_8VMS_NAME BOOST_OS_VMS_NAME

这里的想法是,您正在构建不同的 BOOST_OS_xxx / BOOST_OS_xxx_NAME表单宏,然后将这些宏重新映射到所需的宏。使用数字前缀具有不受扩展影响的优点(此类实体是有效的预处理器令牌(pp-number),但它们不能是类似对象的宏)。