我怎样才能故意丢弃[[nodiscard]]返回值?

spr*_*aff 18 c++ c++17

说我有

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

int main ()
{
    foo ();
}
Run Code Online (Sandbox Code Playgroud)

然后

error: ignoring return value of ‘int foo()’, declared with attribute nodiscard [-Werror=unused-result]
Run Code Online (Sandbox Code Playgroud)

但如果

int x = foo ();
Run Code Online (Sandbox Code Playgroud)

然后

error: unused variable ‘x’ [-Werror=unused-variable]
Run Code Online (Sandbox Code Playgroud)

是否有一种干净的方式告诉编译器"我想丢弃这个[[nodiscard]]值"?

Ale*_*iev 26

CppCoreGuidelines建议使用std::ignore

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

这与另一个答案中的建议几乎相同boost::ignore_unused,但开箱即用std::

然而,使用也有缺点std::ignore

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


Sha*_*our 14

WG14 nodiscard提案讨论了允许诊断通过铸造作废沉默的理由.它表示强制转换为无效是鼓励(如果不是规范的)沉默它的方式,它遵循现有的实现方式__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的枚举类型.除非明确转换为void,否则不鼓励将nodiscard调用作为潜在评估的丢弃值表达式的外观. 在这种情况下,实施应该发出警告.这通常是因为丢弃nodiscard呼叫的返回值具有令人惊讶的后果. - 结束说明]

这是一个注释,因此非规范,但基本上这就是现有实现的功能__attribute__((warn_unused_result)).另外,请注意,nodiscard的诊断也是非规范性的,因此对违反nodiscard的诊断并不是错误的,但实施的质量就像通过强制转换为无效一样.

看到关于nodiscardclang文档,warn_unused_result:

Clang支持在可疑情况下丢弃函数调用表达式的结果时进行诊断的能力.当函数或其返回类型标有[[nodiscard]](或__attribute __((warn_unused_result)))时,会生成诊断,并且函数调用显示为未明确强制转换为void的潜在评估的丢弃值表达式.


Som*_*ken 13

把它投到void:

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

int main ()
{
    static_cast<void>(foo());
}
Run Code Online (Sandbox Code Playgroud)

这基本上告诉编译器" 是的,我知道我放弃了这个,是的,我很确定. "

  • 如果在_几年甚至几十年_的语言中强制要求强制转换为无效的返回值就好了!在进行链接/运行/调试之前,想想在编辑-编译周期中可以避免多少错误(更少生产)! (2认同)
  • @davidbak 除了原始 C 语言中没有 `void`,并且通常的做法是忽略某些库函数(如 `printf`)的返回值。添加显式丢弃这些函数的返回值的要求会破坏当时存在的几乎所有程序。并制作了一些非常不雅观的代码。 (2认同)

Mat*_*her 8

您还可以int使用其他标记标记返回的内容:

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

int main ()
{
    [[maybe_unused]] int i = foo ();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上,我不同意.我故意在我的应用程序上打开警告,因为我不想在任何地方混乱,除非我知道这个属性.不同的政策,不同的方法;) (2认同)
  • 我更喜欢这个解决方案,而不是强制转换为 void,我觉得这有点不直观。我也不认为未使用的变量/参数是无用的,事实上,它有时会在大型遗留代码库中捕获错误,其中函数有数千行(是的,我知道 x-)。只是我的2c。 (2认同)

小智 7

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

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

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

int main ()
{
    discard(foo());
}
Run Code Online (Sandbox Code Playgroud)

故意丢弃 [[nodiscard]] 值。