请考虑以下小功能。它提供了编译器的抽象,可以在程序上突破调试器。
inline constexpr void BreakDebug()
{
#ifdef __GNUC__
__builtin_trap();
#elif defined _MSC_VER
__debugbreak();
#endif
}
我想重写这个函数,用C++20的代码来代替前处理程序的指令。由于 __builtin_trap
和 __debugbreak
是编译器特有的,是相互排斥的,我不能用简单的 if constexpr
因为我会得到一个编译错误。
假设我将编译器宏包装成 __GNUC__
和 _MSC_VER
使用 constexpr
枚举常数......怎么能这样做呢?
显然,这些内置函数也可以变成依赖名。我检查了这个 此处. 因此,通常的技巧,包括使潜在的错误的代码依赖于工作。
enum compiler_t{
gnu,
msvc
};
inline constexpr compiler_t compiler =
#ifdef __GNUC__
compiler_t:: gnu;
#else
compiler_t:: msvc;
#endif
template <class...Args>
inline constexpr void BreakDebug(Args...args)
{
if constexpr (compiler == gnu){
__builtin_trap(args...);
} else {
__debugbreak(args...);
}
}
int main(){
BreakDebug();
return 0;
}
你只需要声明一个不被调用的函数(不需要定义,因为它不会被调用)。
inline constexpr void BreakDebug()
{
#ifdef __GNUC__
constexpr bool GNU = true;
constexpr void __debugbreak();
#elif defined _MSC_VER
constexpr bool GNU = false;
constexpr void __builtin_trap();
#endif
if constexpr (GNU){
__builtin_trap();
} else {
__debugbreak();
}
}
通过只声明那个不存在的、你永远不会调用的函数,你可以在签名不正确的情况下避免链接器错误。