编译器未报错是因为未启用对应警告选项:gcc/clang需加-wunused-result,msvc需/wall或/w4且版本≥vs2017 15.3;[[nodiscard]]仅作用于函数声明、枚举、类,不传播至模板特化或继承重写,忽略时应显式用(void)foo()。
![c++中的属性[[nodiscard]]是什么?(如何强制检查函数返回值)](https://img.php.cn/upload/article/001/431/639/177130461266032.jpg)
为什么 [[nodiscard]] 编译器没报错?
加了 [[nodiscard]] 却没警告,大概率是编译器没开对应诊断开关。GCC/Clang 默认不启用 [[nodiscard]] 检查,必须显式开启:-Wunused-result(GCC/Clang)或 /wd4834(MSVC)。没有这个 flag,[[nodiscard]] 就只是个注释。
- Clang/GCC:加
-Wunused-result后,调用[[nodiscard]]函数但忽略返回值才会触发warning: ignoring return value - MSVC:需启用
/Wall或至少/W4,并注意它对[[nodiscard]]的支持从 VS 2017 15.3 起才稳定 - 函数模板实例化时,
[[nodiscard]]不会自动传播到特化版本,得每个特化都手动加
[[nodiscard]] 能用在哪些地方?
它只对函数声明、枚举类型、类/结构体生效,不能贴在变量、参数或返回类型上。最常见误用是试图修饰 lambda 或局部函数——C++ 标准不允许。
- ✅ 正确:普通函数、成员函数、构造函数(如
[[nodiscard]] MyClass()表示不应忽略构造出的对象)、枚举定义 - ❌ 错误:lambda 表达式、函数指针类型、
auto推导的变量、返回值本身(比如写成[[nodiscard]] int foo()是合法的,但int [[nodiscard]] foo()是非法的) - 注意:C++20 起允许在命名空间作用域加
[[nodiscard("reason")]],字符串字面量会出现在警告里,但 Clang 目前不显示该提示
忽略 [[nodiscard]] 返回值的“合法”方式
不是所有忽略都是 bug;有时你真不需要结果。但必须显式表达意图,否则警告不会消失。
- 最安全:用
(void)强制丢弃,如(void)foo();—— 所有编译器都认,且明确表示“我知道,我不要” - 次选:赋给
[[maybe_unused]]变量,如[[maybe_unused]] auto _ = foo();—— 语义更清晰,但 C++17 起才支持 - 别用
static_cast<void>(foo())</void>:冗长且无额外好处;也别用foo();加注释——编译器不认注释 - 特别注意:如果函数返回
std::optional或自定义类型,而你只关心副作用,仍需显式丢弃;否则警告照常
和 [[nodiscard]] 相关的隐含陷阱
它不检查运行时行为,也不保证返回值“有意义”;它只做一层静态语法检查。很多看似合理的地方其实会失效。
立即学习“C++免费学习笔记(深入)”;
- 重载函数中,只有被调用的那个版本带
[[nodiscard]]才触发警告;其他重载没加,调用时就不会拦 - 继承体系里,基类函数加了
[[nodiscard]],派生类重写后默认不继承该属性,必须重新加 - 头文件中声明加了
[[nodiscard]],但实现文件里定义没加?没关系——属性只看声明,定义处加不加不影响 - 最易忽略:第三方库函数若没加
[[nodiscard]],哪怕它明显不该忽略(比如std::vector::at()),你也无法靠这个机制捕获——得等库作者更新或自己封装一层










