在使用 C++20 的项目中,CLion 建议我添加[[nodiscard]]到我的 const 类方法定义中,例如,
class Test {
public:
[[nodiscard]] int f(int a, int b) const {
return a + b;
}
}
Run Code Online (Sandbox Code Playgroud)
解释是
向成员函数添加 [[nodiscard]] 属性(在 C++17 中引入),以便在编译时突出显示哪些返回值不应被忽略。
我还检查了cppreference.com:
如果从废弃值表达式(而不是强制转换为 void)调用声明为 nodiscard 的函数或按值返回声明为 nodiscard 的枚举或类的函数,则鼓励编译器发出警告。... 出现在函数声明、枚举声明或类声明中。
如果从丢弃值表达式而不是强制转换为 void,
- 调用声明为 nodiscard 的函数,或者
- 调用返回按值声明为 nodiscard 的枚举或类的函数,或者
- 通过显式类型转换或 static_cast 调用声明为 nodiscard 的构造函数,或者
- 声明为 nodiscard 的枚举或类类型的对象通过显式类型转换或 static_cast 进行初始化,
鼓励编译器发出警告。
老实说,我不太明白为什么这个位置需要这个注释。如果调用者进一步处理它们,为什么编译器会忽略我的返回值?是否有一个直观的解释来解释它到底告诉编译器什么以及为什么需要它?
假设我有这门课:
class [[nodiscard]] MyClass
{
public:
MyClass() : _x(x) {}
MyClass(int x) : _x(x) {}
private:
int _x;
};
Run Code Online (Sandbox Code Playgroud)
将标签单独添加[[nodiscard]]到类的构造函数中会改变什么吗?或者这对于[[nodiscard]]应用于类声明本身的标签来说是完全多余的,因此只会给头文件添加不必要的噪音?
(我的测试表明后者,但我可能会错过一些细微差别)
该[[nodiscard]]属性对于操作员来说是必需的吗?或者可以安全地假设编译器会发出警告,就像它对大多数可疑丢弃的东西所做的那样?
例如,一个重载的operator+,应该应用该属性吗?函数转换运算符或新运算符等特殊运算符又如何呢?什么时候迂腐了?
我想使用第三方函数,它通过充满函数指针的结构提供其 API。例如:
struct S {
using p_func1 = int(*)(int, int);
p_func1 func1;
using p_func2 = int(*)(char*);
p_func2 func2;
}
Run Code Online (Sandbox Code Playgroud)
第三方库初始化该结构。需要检查这些函数(func1、func2)的返回值,我希望能够以某种方式在属性上体现出来,[[discard]]以确保返回值得到检查。
有什么办法可以做到这一点,同时保持结构的 ABI?
编辑:到目前为止,我能想到的最好的办法就是拥有另一个结构,如下所示:
struct S_wrap {
S orig;
[[nodiscard]] int func1(int a, int b){ return orig.func1(a, b); }
[[nodiscard]] int func2(char* a){ return orig.func2(a); }
}
Run Code Online (Sandbox Code Playgroud)
我希望有更好的东西
从 C++20 开始,[[nodiscard]]可以应用于构造函数。http://wg21.link/p1771有示例:
struct [[nodiscard]] my_scopeguard { /* ... */ };
struct my_unique {
my_unique() = default; // does not acquire resource
[[nodiscard]] my_unique(int fd) { /* ... */ } // acquires resource
~my_unique() noexcept { /* ... */ } // releases resource, if any
/* ... */
};
struct [[nodiscard]] error_info { /* ... */ };
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
my_scopeguard(); // warning encouraged
(void)my_scopeguard(), // warning not encouraged, cast to void …Run Code Online (Sandbox Code Playgroud) C++17具有nodiscard防止人们忽略函数返回值的属性。
将其添加到代码库中的每个函数中似乎有些过分了。
是否有一个标志告诉 Clang 默认强制执行此操作?
我想将一个类标记为 nodiscard,但将某个函数的返回值排除在 nodiscard 要求之外。这是我的目标:
enum class [[nodiscard]] Result {
OK1,
OK2,
ERROR,
};
[[ok-to-discard]] // This attribute is made up to illustrate my need.
Result doSomethingThatCannotFail() {
// The function can return OK1 or OK2, but the caller may or may not care.
// The function cannot return ERROR.
// Therefore, it's OK to discard this particular Result return value,
// even though in general Result should not be ignored.
}
Run Code Online (Sandbox Code Playgroud)
我不认为在每个调用站点添加 ok-to-discard 是一个好主意(这由 如何故意丢弃 [[nodiscard]] 返回值? 涵盖):
您可以使用该属性声明一个类[[nodiscard]]。当您从此类的语义中知道每当它从函数返回时,它必须用于某些用途时,它可能会很有用。[[nodiscard]]我正是遇到这种情况,用它来标记类而不是返回它的每个单独的函数会非常方便。然而,有一个复杂的问题。这是我需要制作的类型[[nodiscard]]:
using ConnectionStruct = std::pair<std::shared_ptr<CMutex>, std::shared_ptr<SignalFunction>>;
Run Code Online (Sandbox Code Playgroud)
是否有语法将 my 标记ConnectionStruct为[[nodiscard]]?
#include <iostream>
#include <memory>
class A
{
public:
static [[nodiscard]] std::unique_ptr<A> create();
virtual int get_version() = 0;
virtual ~A() = default;
};
class B : public A
{
public:
[[nodiscard]] int get_version() override
{
return 20;
}
};
std::unique_ptr<A>
A::create()
{
return std::make_unique<B>();
}
int main()
{
auto a = A::create();
[[maybe_unused]] int v = a->get_version();
}
Run Code Online (Sandbox Code Playgroud)
我尝试使用[[nodiscard]]不允许忽略 的返回值A::create()。但是,我在 GCC 和 Clang 中得到不同的编译输出。
尝试过
海湾合作委员会:
<source>:7:12: warning: attribute …Run Code Online (Sandbox Code Playgroud) (我承认这个问题是基于意见的,但可能是需要考虑的方法和指南。)
[[nodiscard]]作为对编译器以及随后对开发人员的警告,表明该函数的返回值很重要并且应该使用或捕获。
什么是更好的做法(在早期阶段检测可能的错误):将[[nodiscard]]属性应用于返回值的任何成员函数(特殊情况除外)?...或者仅将其应用于必要的成员函数(例如:返回内存分配的成员函数)?