如何编写可被编译器适配的C++ Contracts?宏与编译选项疑问
C++ Contracts 编写与兼容指南
一、标准合规的Contracts编写方式
C++20标准中,Contracts通过带参数的属性实现,正确语法如下:
- 前置条件(
expects):约束函数调用前必须满足的条件,放在函数参数列表之后、函数体之前 - 后置条件(
ensures):约束函数返回时必须满足的条件,位置与expects一致
示例代码:
// 前置条件:传入指针不能为空 void process(X* x) [[expects: x != nullptr]] { // 函数逻辑 } // 后置条件:返回时x的u成员必须大于0 int calculate(X* x) [[ensures: x->u > 0]] { x->u = 42; return x->u; }
注意:你提到的float f(X *x)[[expects:x]]属于旧草案写法,已被标准废弃,需使用上述标准语法。
二、无Contracts支持的编译器兼容方案
直接写[[expects:...]]或[[ensures:...]]会在不支持的编译器上触发语法错误——旧编译器不支持带参数的属性语法,无法像普通未知属性那样忽略。因此必须通过条件编译宏包装Contracts代码,让无支持的编译器自动跳过。
推荐的宏包装实现
无需手动定义USE_CONTRACTS,直接利用编译器的特性检测宏自动判断:
// 检测标准C++20 Contracts支持 #if defined(__cpp_contracts) #define EXPECTS(cond) [[expects: cond]] #define ENSURES(cond) [[ensures: cond]] // GCC实验性支持(需加-fcontracts编译选项) #elif defined(__GCC_CONTRACTS) #define EXPECTS(cond) [[expects: cond]] #define ENSURES(cond) [[ensures: cond]] // Clang实验性支持(需加-fcxx-contracts编译选项) #elif defined(__clang_contracts) #define EXPECTS(cond) [[expects: cond]] #define ENSURES(cond) [[ensures: cond]] // 无支持时,宏展开为空 #else #define EXPECTS(cond) #define ENSURES(cond) #endif // 实际使用 void process(X* x) EXPECTS(x != nullptr) { // ... } int calculate(X* x) ENSURES(x->u > 0) { // ... }
三、特性检测宏说明
存在无需手动传入编译选项的自动特性检测宏:
__cpp_contracts:C标准规定的特性检测宏,编译器支持C20 Contracts时会自动定义(值为对应标准版本号,如201907L)- 编译器扩展宏:
- GCC:
__GCC_CONTRACTS,需开启编译选项-fcontracts才会定义 - Clang:
__clang_contracts,需开启编译选项-fcxx-contracts才会定义
- GCC:
注意:即使编译器支持C++20,默认可能不启用Contracts检查,仍需手动添加编译选项激活,但宏的检测是自动的,无需用户额外定义USE_CONTRACTS。
四、关键注意事项
- 不要直接使用带参数的Contracts属性,必须用宏包装,否则旧编译器会报语法错误
- 不同编译器的Contracts编译选项不同,需根据目标编译器调整(如GCC用
-fcontracts,Clang用-fcxx-contracts) - 目前主流编译器对C++20 Contracts的支持仍处于实验阶段,部分特性可能未完全实现
内容的提问来源于stack exchange,提问作者A Pacific Spammer
相关产品推荐
相关产品推荐

