我正在努力将许多宏转换为(范围内的,类型安全的)const值。我的目标是在必要时使用if constexpr
。
目前,我已经设法使用stringify宏和模板函数获得了一些令人满意的结果:
#define STRINGIFY(X) #X
#define TO_STRING(X) STRINGIFY(X)
上面的宏有一个令人惊讶的不同的行为,具体取决于给定的参数:
std::cout << TO_STRING(_DEBUG) << '\n';
显示_DEBUG
是否(且仅当)宏_DEBUG
未定义,但如果已定义则显示宏值(如果已定义,则显示空字符串,但不显示值)。
无论如何,宏结果总是text literal所以我使用constexpr
函数检查结果:
template <int SIZE>
constexpr bool b(const char (&definition)[SIZE])
{
return definition[0] != '_';
}
现在合并STRINGIFY
和b
,可以创建枚举并在if constexpr
中使用它们(而不是使用#ifdef
个链):
enum operating_system : bool
{
iOS = b(TO_STRING(__APPLE__)),
Windows = b(TO_STRING(__MINGW32__)),
Linux = b(TO_STRING(__linux__)),
};
int main()
{
if constexpr (operating_system::Windows)
{
// Specific Windows stuff.
}
else if constexpr (operating_system::iOS)
{
// Specific iOS stuff.
}
// Platform-independent sutff.
return 0;
}
我不喜欢使用辅助函数将文字转换为bool值(b
函数),但这并不是什么大问题。真正的问题是它依赖于检测起始下划线(_
)以便检测不存在的宏。因此,具有以下划线开头的值的现有宏将是误报。此外,宏的实际值丢失了,让我们看一个例子:
#define _DEBUG 0
#define DRIVERS _09072007
template <int SIZE>
constexpr int i(const char (&definition)[SIZE])
{
return definition[0] != '_'; // what shall I put here?...
}
enum stuff : int
{
cpp_version = i(TO_STRING(__cplusplus)),
debug_enabled = i(TO_STRING(_DEBUG)),
drivers_version = i(TO_STRING(DRIVERS)),
};
int main()
{
std::cout << "C++ version: " << stuff::cpp_version << '\n'
<< "Debug mode: " << stuff::debug_enabled << '\n'
<< "Drivers version: " << stuff::drivers_version << '\n';
return 0;
}
上面的代码显示:
C++ version: 1 Debug mode: 1 Divers version: 0
预期但不满意。我需要一种方法将这些字符串文字转换为实际值(在编译时),以及“{em>它存在,如果不是以下划线开头”的天真方法的解决方法{{1}宏显示(可能忽略非数字值,直到找到数值?)。
我尝试过递归方法,但索引字符串文字不是常量表达式:
DRIVERS