如何使用#pragma 实现 RAII?

问题描述 投票:0回答:2

目前,我有以下代码:

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){

这是为什么呢?可以实现我想要的吗?

c++ pragma raii
2个回答
1
投票

不,在进行任何编译之前,所有预处理器指令都会被读取和解释(这实际上是某些编译器上的单独步骤)。换句话说,您的

#pragma
已经应用到您在代码中在开始部分和结束部分之间看到的行。

您似乎需要的是源代码生成,这需要一个额外的工具来预处理您的文件并将这些语句插入到您想要的位置(或者使用允许您注入钩子的编译器以在构建时生成它们) ,就像叮当声)。


1
投票

编译指示是由过早的翻译阶段处理的,无法将诸如保护对象之类的东西应用于块。你能做的最好的事情就是编写宏来减少样板代码

#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
from 指令,将编译指示嵌入到其他扩展中。
DIAG_ERR_PUSH(...)
取代您的保护对象,并且
DIAG_POP()
界定区域(而不是花括号)。

不完全是 RAII,但肯定比必须键入 all 的 pragma 细节要好。 这是一个活生生的例子

© www.soinside.com 2019 - 2024. All rights reserved.