如何故意丢弃 [[nodiscard]] 返回值?

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

说我有

[[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]]
值”?

c++ c++17 nodiscard
6个回答
54
投票

将其投射到

void
:

[[nodiscard]] int foo ()
{
    return 0;
}

int main ()
{
    static_cast<void>(foo());
}

这基本上告诉编译器“是的,我知道我要放弃这个,是的,我确定它。


37
投票

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 时,会生成诊断信息.


26
投票

CppCoreGuidelines 建议使用

std::ignore

切勿强制转换为

(void)
来忽略
[[nodiscard]]
返回值。如果您故意想要丢弃这样的结果,请首先认真考虑这是否真的是一个好主意(函数或返回类型的作者首先使用
[[nodiscard]]
通常是有充分理由的)。如果您仍然认为它是合适的并且您的代码审查者同意,请使用
std::ignore =
关闭警告,这是简单、可移植且易于 grep 的。

这与另一个答案中建议的

boost::ignore_unused
几乎相同,但超出了
std::
框。

但是,使用

std::ignore
也有缺点:

  • 与其他此类辅助函数一样,它会实例化,花费编译时间,并被调用(在非优化调试中),花费运行时间
  • std::ignore
    用于另一个目的1
  • std::ignore
    甚至不能保证抑制警告

1P2968R2 论文被批准为 C++26。它将

std::ingore
移出
<tuple>
标头,并更详细地指定它,因此它可以实现其他用途。尽管如此,本文并不认可使用
std::ignore
来抑制未使用的参数警告。


22
投票

您还可以使用另一个标签来标记返回的

int

[[nodiscard]] int foo ()
{
    return 0;
}

int main ()
{
    [[maybe_unused]] int i = foo ();
}

如果您有一些需要该值的仅调试代码,可能会很有用。


12
投票

我使用(空)辅助函数“discard”

template<typename T>
void discard(const T&) {}

[[nodiscard]] int foo ()
{
    return 0;
}

int main ()
{
    discard(foo());
}

故意丢弃 [[nodiscard]] 值。


3
投票

带升压

#include <boost/core/ignore_unused.hpp>
int main ()
{
    boost::ignore_unused(foo ());
}

boost::ignore_unused
通过引用 const 获取其参数,因此参数必须是可以绑定到 const 引用的东西。 我相当确定任何可以作为函数返回类型的东西(当然除了 void 之外!)在这里都应该没问题。

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