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

Is it possible to ignore [[nodiscard]] in a special case?

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

假设我有一个 Result 结构,它有这个属性:

struct [[nodiscard]] Result {
};

现在,如果我调用 returns Result 的函数,如果我不检查 returned Result,我会收到警告:

Result someFunction();

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

此程序生成:

warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]

到目前为止,还不错。现在假设,我有一个特殊的功能,我仍然想要 return Result,但我不希望生成此警告,如果省略检查:

Result someNonCriticalFunction();

int main() {
    someNonCriticalFunction(); // I don't want to generate a warning here
}

这是因为,someNonCriticalFunction() 做了一些不重要的事情(例如,像 printf - 我打赌没有人检查 printf 的 return始终保持价值);大多数情况下,我不在乎它是否失败。但我仍然希望它 return Result,因为在极少数情况下,我确实需要它 Result.

有没有办法做到这一点?


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

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

template <bool nodiscard=true>
struct Result;

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

template <>
struct [[nodiscard]] Result<true>
    : Result<false>
{
    using Result<false>::Result;
};

这有效地使 Result 有条件地 [[nodiscard]],它允许:

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

int main() {
    someFunction();            // warning here
    someNonCriticalFunction(); // no warning here
}

虽然实际上,这与:

  • removing [[nodiscard]] from Result, and add it to every function which returns Result

首先让我投票。

我推荐你排除的选项:

"removing [[nodiscard]] from Result, and add it to every function which returns Result."

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

struct [[nodiscard]] Result {
};

struct DiscardableResult: public Result {
};

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

Result func1();
DiscardableResult func2();

func1(); // will warn
func2(); // will not warn

将结果转换为 (void *)。

int main()
{
    (void *)someFunction(); //Warning will be gone.
}

就编译器而言,这样您就“使用”了您的结果。非常适合当您使用的库已经使用了 nodiscard 并且您真的不想知道结果时。

为什么不使用 <tuple> header 中的 std::ignore——这会使丢弃变得明确:

[[nodiscard]] int MyFunction() { return 42; }

int main() 
{
    std::ignore = MyFunction();
    return 0;
}