[[nodiscard]] 仅是编译器警告提示而非强制约束,其效果依赖编译器配置(如-Werror=unused-result)、项目开关及CI门禁,C++20支持带消息的写法提升可读性。
![c++17 [[nodiscard]] 属性怎么强制调用者不能忽视函数返回值](https://img.php.cn/upload/article/001/221/864/179305388527709.png)
它不能强制,只能让编译器在返回值被忽略时发出警告——是否报错、是否拦截,完全取决于编译器配置和项目开关。
为什么 [[nodiscard]] 不是“强制”,而只是“提醒”
[[nodiscard]] 是一个标准属性(attribute),不是语言约束。它的作用对象是编译器,而非运行时或链接器。C++ 标准只要求编译器“鼓励报错或警告”,不规定必须报错、也不禁止忽略。
- Clang/GCC 默认在
-Wall或-Wreturn-type下触发-Wunused-result警告 - MSVC 对应警告是
C4834,需开启/W4或更高警告级别 - 若未启用对应警告选项(比如只用
-O2编译),[[nodiscard]]完全静默生效 - 即使开了警告,用户仍可用
(void)func()或[[maybe_unused]] auto r = func();显式绕过
怎么让警告真正“拦住”构建流程
要让 [[nodiscard]] 发挥实际拦截效果,必须配合编译器的“警告转错误”机制:
- GCC/Clang:加
-Werror=unused-result(比-Werror更精准,避免误伤其他警告) - MSVC:加
/WX(将所有警告视为错误),或单独启用/we4834 - CMake 中推荐写法:
target_compile_options(my_target PRIVATE -Werror=unused-result) - 注意:全局开
-Werror风险大,建议只对unused-result精确升级
哪些地方加了 [[nodiscard]] 才真有用
不是所有函数都适合加;加错位置等于白加,甚至引发误报:
立即学习“C++免费学习笔记(深入)”;
- 只在头文件声明处加即可,
.cpp定义中无需重复——属性只绑定声明 - 工厂函数、资源创建函数必须加:
[[nodiscard]] std::unique_ptr<connection> connect();</connection> - 状态检查函数建议加:
[[nodiscard("check before sending")]] bool is_ready() const; - 避免给纯计算函数加:
[[nodiscard]] int square(int x)会干扰调试临时调用 - 派生类重写
[[nodiscard]]成员函数时,必须显式重新标注,否则丢失语义
C++20 带消息的写法能减少误判
带字符串参数的写法不只是“好看”,它能显著提升警告可读性,降低开发者绕过意愿:
[[nodiscard("must check error code")]] ErrorCode write_file(const char* path);- Clang 和 GCC 会在警告里直接显示该字符串,比如:
warning: ignoring return value of function declared with 'nodiscard' attribute: 'must check error code' - 比空泛的“nodiscard”更有上下文,尤其适合跨团队协作或 SDK 接口
- 注意:字符串内容不参与编译逻辑,仅作提示;C++17 不支持该语法,必须用 C++20 起
真正起作用的从来不是属性本身,而是你是否把警告纳入 CI 构建门禁、是否在团队规范里明确“禁止显式丢弃关键返回值”。否则,(void)foo() 一行就能绕过所有设计意图。


















