我正在尝试将操作系统和编译器名称作为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##)(...
这样的事情也无济于事,因为它似乎在以后的升级中得到了扩展。
如何完全避免序列中的扩展?
答案 0 :(得分:2)
由于您依赖未定义的令牌VMS
,因此快速解决方案很简单#undef VMS
。显然,为了避免破坏依赖于该宏的代码,您应该将Boost PP代码放在自己的.cpp文件中。
答案 1 :(得分:2)
如何完全避免序列中的扩展?
你做不到。将高级数据结构作为参数传递给宏必然涉及评估数据结构。
你可以避免这个问题,并且仍然基本上以三种方式使用boost宏:
这基本上是MSalters推荐的。
这个想法是,如果没有定义VMS
,它的评估就不会扩展它。
在这里,你冒着VMS
未定义的风险,这可能会产生可怕的后果,所以你必须减轻它(MSalters对此有所了解)。
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_FOO
和BOOST_OS_FOO_NAME
的不同共享部分来放入您的数据,这样您的数据就不会包含您定义的宏。
在这里,您可能会在某个更高级别定义S_FOO
的风险使您陷入困境。您可以通过查找要在数据中使用的其他部分来缓解此问题。
这最容易通过示例来定义:
#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),但它们不能是类似对象的宏)。