提问人:neutrion 提问时间:11/1/2023 最后编辑:Remy Lebeauneutrion 更新时间:11/1/2023 访问量:93
如何用 #pragma 实现 RAII?
How to achieve RAII with #pragma's?
问:
目前,我有以下一段代码:
enum class Letters {
A,
B,
C
};
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"
Letters e(Letters::A);
switch(e){
case Letters::A: break;
case Letters::B: break;
}
#pragma GCC diagnostic pop
我想使用这样的东西:
class DiagnosticError {
public:
constexpr DiagnosticError() {
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"
}
constexpr ~DiagnosticError() {
#pragma GCC diagnostic pop
}
};
enum class Letters {
A,
B,
C
};
{
constexpr DiagnosticError switchError;
Letters e(Letters::A);
switch(e){
case Letters::A: break;
case Letters::B: break;
}
}
该代码在 C++20 下编译良好,但不会生成错误:
error: enumeration value 'C' not handled in switch [-Werror=switch]
38 | switch(e){
为什么?有可能实现我想要的吗?
答:
1赞
Blindy
11/1/2023
#1
不,在进行任何编译之前,所有预处理器指令都会被读取和解释(这实际上是某些编译器上的一个单独步骤)。换言之,你已经完全应用于你在代码中看到的开始部分和结束部分之间的行。#pragma
你所追求的是源代码生成,这需要一个额外的工具来预处理你的文件,并将这些语句插入到你想要的地方(或者使用一个编译器,允许你在构建时注入钩子来生成它们,比如clang)。
1赞
StoryTeller - Unslander Monica
11/1/2023
#2
编译指示的处理时间过早,无法将保护对象之类的东西应用于块。你能做的最好的事情就是编写你的宏,在样板上剪掉一点
#define DIAG_ERR_PUSH(flags) _Pragma("GCC diagnostic push") DIAG_ERR_PUSH_(GCC diagnostic error flags)
#define DIAG_ERR_PUSH_(str) _Pragma(#str)
#define DIAG_POP() _Pragma("GCC diagnostic pop")
enum class Letters {
A,
B,
C
};
DIAG_ERR_PUSH("-Wswitch")
Letters e(Letters::A);
switch(e){
case Letters::A: break;
case Letters::B: break;
}
DIAG_POP()
从 C++11 开始,我们有了指令的形式,将编译指示嵌入到其他扩展中。 代替守卫对象,并划定区域(而不是大括号)。_Pragma
DIAG_ERR_PUSH(...)
DIAG_POP()
不完全是 RAII,但肯定比必须为实用语输入所有细节要好。这是一个活生生的例子。
评论