说我有
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
foo ();
}
然后
error: ignoring return value of ‘int foo()’, declared with attribute nodiscard [-Werror=unused-result]
但是如果
int x = foo ();
然后
error: unused variable ‘x’ [-Werror=unused-variable]
有没有一种干净的方式告诉编译器“我想丢弃这个
[[nodiscard]]
值”?
将其投射到
void
:
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
static_cast<void>(foo());
}
这基本上告诉编译器“是的,我知道我要放弃这个,是的,我确定它。”
WG14 不丢弃提案讨论了允许通过强制转换为 void 来沉默诊断的基本原理。它说强制转换为 void 是鼓励(如果非规范的话)使其沉默的方式,这遵循现有实现对
__attribute__((warn_unused_result))
: 的处理方式
[[nodiscard]] 属性在现实世界中具有广泛的用途,由 Clang 和 GCC 实现为 __attribute__((warn_unused_result)) ,但由 WG21 以 [[nodiscard]] 的名称进行标准化。本提案选择了标识符nodiscard 因为偏离这个名称会造成与 C++ 不必要的不兼容。
该属性的语义很大程度上依赖于使用的概念, 其定义由实施自行决定。然而, WG21 指定的非规范性指导旨在鼓励 当 nodiscard 函数出现时发出警告诊断的实现 调用用于潜在评估的丢弃值表达式 除非它显式转换为 void。这意味着一个 不鼓励实现执行数据流分析(如 需要初始化但未使用的局部变量诊断)。 ...
C++ 方式是
static_cast<void>
。
请参阅 C++ 标准草案 [[dcl.attr.nodiscard]p2:
[ 注意:nodiscard 调用是一个函数调用表达式,它调用先前声明的 nodiscard 函数,或者其返回类型是可能的 cv 限定类或标记为 nodiscard 的枚举类型。 不鼓励将 nodiscard 调用作为潜在评估的丢弃值表达式出现 除非显式转换为 void。 在这种情况下,实施应发出警告。 这通常是因为丢弃 nodiscard 调用的返回值会产生令人惊讶的后果。 — 尾注]
这是一个注释,因此不规范,但基本上这是现有实现对
__attribute__((warn_unused_result))
所做的事情。另外,请注意,对 nodiscard 的诊断也是非规范的,因此违反 nodiscard 的诊断并不是格式错误,而是实现的质量,就像通过强制转换为 void 进行抑制一样。
请参阅 clang 文档中关于 nodiscard、 warn_unused_result 的内容:
Clang 支持诊断函数调用表达式的结果在可疑情况下何时被丢弃的能力。当函数或其返回类型标有 [[nodiscard]] (或 __attribute__((warn_unused_result))) 且函数调用显示为潜在评估的丢弃值表达式 未显式转换为 void 时,会生成诊断信息.
CppCoreGuidelines 建议使用
std::ignore
:
切勿强制转换为
来忽略(void)
返回值。如果您故意想要丢弃这样的结果,请首先认真考虑这是否真的是一个好主意(函数或返回类型的作者首先使用[[nodiscard]]
通常是有充分理由的)。如果您仍然认为它是合适的并且您的代码审查者同意,请使用[[nodiscard]]
关闭警告,这是简单、可移植且易于 grep 的。std::ignore =
这与另一个答案中建议的
boost::ignore_unused
几乎相同,但超出了std::
框。
但是,使用
std::ignore
也有缺点:
std::ignore
用于另一个目的1std::ignore
甚至不能保证抑制警告1 有 P2968R2 论文被批准为 C++26。它将
std::ingore
移出 <tuple>
标头,并更详细地指定它,因此它可以实现其他用途。尽管如此,本文并不认可使用 std::ignore
来抑制未使用的参数警告。
您还可以使用另一个标签来标记返回的
int
:
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
[[maybe_unused]] int i = foo ();
}
如果您有一些需要该值的仅调试代码,可能会很有用。
我使用(空)辅助函数“discard”
template<typename T>
void discard(const T&) {}
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
discard(foo());
}
故意丢弃 [[nodiscard]] 值。
带升压:
#include <boost/core/ignore_unused.hpp>
int main ()
{
boost::ignore_unused(foo ());
}
boost::ignore_unused
通过引用 const 获取其参数,因此参数必须是可以绑定到 const 引用的东西。 我相当确定任何可以作为函数返回类型的东西(当然除了 void 之外!)在这里都应该没问题。