在特殊情况下是否可以忽略[[nodiscard]]?

gez*_*eza 1 c++ c++17

C++ 17有一个新属性[[nodiscard]].

假设我有一个Result结构,它具有以下属性:

struct [[nodiscard]] Result {
};
Run Code Online (Sandbox Code Playgroud)

现在,如果我调用一个返回的函数,Result如果我不检查返回的,我会收到警告Result:

Result someFunction();

int main() {
    someFunction(); // warning here, as I don't check someFunction's return value
}
Run Code Online (Sandbox Code Playgroud)

该程序生成:

警告:忽略使用'nodiscard'属性声明的函数的返回值[-Wunused-result]

到现在为止还挺好.现在假设,我有一个特殊的功能,我仍然想要返回Result,但如果省略检查,我不希望生成此警告:

Result someNonCriticalFunction();

int main() {
    someNonCriticalFunction(); // I don't want to generate a warning here
}
Run Code Online (Sandbox Code Playgroud)

这是因为,someNonCriticalFunction()做了一些不重要的事情(例如,类似的事情printf- 我敢打赌,没有人会一直检查其printf返回值); 大多数情况下,我不在乎它是否失败.但我还是希望它能够回归Result,就像在极少数情况下,我确实需要它Result.

有可能以某种方式这样做吗?


我不喜欢可能的解决方案:

  • 我不想把它称为(void)someNonCriticalFunction(),因为这个函数被调用了很多次,它很尴尬
  • 创建一个包装器someNonCriticalFunction(),它调用(void)someNonCriticalFunction():我不想因为这个而拥有一个不同的命名函数
  • [[nodiscard]]从Result中删除,并将其添加到每个返回的函数中Result

Joh*_*ski 34

为什么不利用header\xe2\x80\x94std::ignore中的内容来<tuple>明确丢弃:

\n
[[nodiscard]] int MyFunction() { return 42; }\n\nint main() \n{\n    std::ignore = MyFunction();\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

  • OP 说他不想使用 `(void)MyFunction()` 因为它被调用了很多而且很“尴尬”,但是在所有调用前面加上 `std::ignore =` 比 `(void) 还要额外的语法)`,并添加一个 `&lt;tuple&gt;` 依赖项。我认为他只能忍气吞声。结果结构很烦人,有时这就是生活。 (4认同)
  • @BillyDonahue 当然,OP 必须忍住。鉴于此,他们可能会记得需要编写富有表现力且意图明确的代码。`(void)MyFunction();` **不**表达意图,并且在审查过程中可能会忽略其效果。`std::ignore = MyFunction();` 不会受到这些影响。 (4认同)
  • @sehe `(void)` 与 C 兼容,众所周知且惯用,并且更通用。它可以应用于可能已经是“void”表达式的表达式。`std::ignore` 具有与元组相关的目的,并且当它用于非设计目的时,其意图更加模糊。 (4认同)
  • 原始指针、错误代码和大量已经消失的习语也是如此。如果你想争辩说英语单词没有表达力,那就继续吧,但我说的是你的到达。std::ignore 的好处是表达意图。这几乎很有趣,因为“忽略”这个词也有其目的。我想说你可以用它来表达它的含义。 (4认同)
  • 我真的很喜欢这个解决方案。它写起来很快,而且很明显它在做什么。另外,当您想要正确解决问题时,可以轻松搜索! (3认同)

Bar*_*rry 5

他们说计算机科学中的每个问题都可以通过添加另一层间接来解决:

template <bool nodiscard=true>
struct Result;

template <>
struct Result<false> {
    // the actual implementation
};

template <>
struct [[nodiscard]] Result<true>
    : Result<false>
{
    using Result<false>::Result;
};
Run Code Online (Sandbox Code Playgroud)

这有效地Result有条件地进行[[nodiscard]],这允许:

Result<true> someFunction();
Result<false> someNonCriticalFunction();

int main() {
    someFunction();            // warning here
    someNonCriticalFunction(); // no warning here
}
Run Code Online (Sandbox Code Playgroud)

虽然真的,但这与:

  • [[nodiscard]]从Result中删除,并将其添加到返回Result的每个函数中

这让我开始投票.

  • 现在他必须转到返回“Result”的所有函数,并将它们更改为“Result&lt;true&gt;”。但如果他要这样做,他也可以将 `[[nodiscard]]` 添加到函数中(这确实是他应该做的,只是他武断地排除了该解决方案)。 (2认同)

Nik*_* C. 5

我推荐你排除的选项:

“删除[[nodiscard]]Result,并把它添加到每一个返回结果的功能。”

但是由于您似乎对此不满意,这里有另一种解决方案,使用沼泽标准继承:

struct [[nodiscard]] Result {
};

struct DiscardableResult: public Result {
};
Run Code Online (Sandbox Code Playgroud)

对于可以丢弃结果的函数,使用DiscardableResult作为返回类型:

Result func1();
DiscardableResult func2();

func1(); // will warn
func2(); // will not warn
Run Code Online (Sandbox Code Playgroud)

  • @geza:您问的是如何不必检查某些东西,据说,*“必须始终检查”*。这是一个矛盾。 (4认同)
  • @geza:“*顺便说一句,你为什么建议为每个函数添加 [[nodiscard]]?*”如果丢弃类型是合理的,那么类型不应该是 `[[nodiscard]]`。这就是将 `[[nodiscard]]` 应用到类型的意义:类型本身的本质意味着你应该*永远*丢弃它。 (3认同)
  • @geza:*“因为它总是存储错误条件,所以必须始终检查它”* - 您的问题与此相矛盾。 (3认同)