c++ 在特殊情况下可以忽略[[nodecard]]吗?

kiz8lqtg  于 2022-12-15  发布在  其他
关注(0)|答案(5)|浏览(159)

C++17有一个新的属性[[nodiscard]]
假设我有一个Result结构体,它有以下属性:

struct [[nodiscard]] Result {
};

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

Result someFunction();

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

此程序生成:
警告:忽略使用“nodiscard”属性声明的函数的返回值[-Wunused-result]
到目前为止,一切顺利。现在假设,我有一个特殊函数,我仍然希望返回Result,但我不希望生成这个警告,如果省略检查:

Result someNonCriticalFunction();

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

这是因为,someNonCriticalFunction()做了一些非关键的事情(例如,类似printf的事情-我敢打赌没有人一直检查printf的返回值);大多数情况下,我不在乎它是否失败,但我仍然希望它返回Result,因为在一些罕见的情况下,我确实需要它的Result
有可能以某种方式做到这一点吗?
我不喜欢的可能解决方案:

  • 我不想把它叫做(void)someNonCriticalFunction(),因为这个函数被调用了很多次,很别扭
  • someNonCriticalFunction()周围创建一个 Package 器,该 Package 器调用(void)someNonCriticalFunction():我不想因为这个函数而使用不同的名称
  • 从Result中删除[[nodiscard]],并将其添加到每个返回Result的函数中
r3i60tvu

r3i60tvu1#

为什么不使用<tuple>头文件中的std::ignore-这将使丢弃显式化:

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

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

mi7gmzs62#

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

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
}

尽管实际上,这与以下内容相同:

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

这让我投了第开始票。

2lpgd968

2lpgd9683#

我推荐你排除的选择:
Result中删除[[nodiscard]],并将其添加到每个返回结果的函数。
但是,既然您看起来并不满意,这里有另一个解决方案,使用bog标准继承:

struct [[nodiscard]] Result {
};

struct DiscardableResult: public Result {
};

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

Result func1();
DiscardableResult func2();

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

t1rydlwq4#

将结果强制转换为(void *)。

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

这样就“使用”了编译器的结果,当你使用一个已经使用了nodecdiscard的库,并且你真的不想知道结果时,这是很好的方法。

5rgfhyps

5rgfhyps5#

您可以使用另一个C++17属性来隐藏警告:可能未使用

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

int main()
{
    [[maybe_unused]] auto v = MyFunction();
    return 0;
}

通过这种方式,您还可以避免std::ignore附带的对std::tuple的混乱依赖,甚至CppCoreGuidelines也公开推荐使用std::ignore来忽略[[nodiscard]]值:
不要强制转换为(void)来忽略nodecard返回值。如果你有意要丢弃这样的结果,首先要仔细考虑这是否是个好主意(通常函数或返回类型的作者一开始使用nodecard是有充分理由的)。如果你仍然认为这是合适的,并且你的代码评审员也同意,可以使用std::ignore =关闭警告,这是简单的,可移植的,并且易于grep。
查看C++参考,正式的std::ignore仅指定在std::tie中解包元组时使用。
虽然std::tie之外的std::ignore的行为没有被正式指定,但是一些代码指南建议使用std::ignore来避免nodecard函数未使用的返回值发出警告。

相关问题