Say I have
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
foo ();
}
then
error: ignoring return value of ‘in
The WG14 nodiscard proposal discusses the rationale for allowing the diagnostic to be silenced by casting to void. It says casting to void is the encouraged (if non-normative) way to silence it which follows what the existing implementation do with __attribute__((warn_unused_result))
:
The [[nodiscard]] attribute has extensive real-world use, being implemented by Clang and GCC as __attribute__((warn_unused_result)) , but was standardized under the name [[nodiscard]] by WG21. This proposal chose the identifier nodiscard because deviation from this name would create a needless incompatibility with C++.
The semantics of this attribute rely heavily on the notion of a use, the definition of which is left to implementation discretion. However, the non-normative guidance specified by WG21 is to encourage implementations to emit a warning diagnostic when a nodiscard function call is used in a potentially-evalulated discarded-value expression unless it is an explicit cast to void. This means that an implementation is not encouraged to perform dataflow analysis (like an initialized-but- unused local variable diagnostic would require). ...
The C++ way would be static_cast<void>
.
See the draft C++ standard [[dcl.attr.nodiscard]p2:
[ Note: A nodiscard call is a function call expression that calls a function previously declared nodiscard, or whose return type is a possibly cv-qualified class or enumeration type marked nodiscard. Appearance of a nodiscard call as a potentially-evaluated discarded-value expression is discouraged unless explicitly cast to void. Implementations should issue a warning in such cases. This is typically because discarding the return value of a nodiscard call has surprising consequences. — end note]
This is a note, so non-normative but basically this is what existing implementations do with __attribute__((warn_unused_result))
. Also, note a diagnostic for nodiscard is also also non-normative, so a diagnostic for violating nodiscard is not ill-formed but a quality of implementation just like suppressing via a cast to void is.
see the clang document on nodiscard, warn_unused_result:
Clang supports the ability to diagnose when the results of a function call expression are discarded under suspicious circumstances. A diagnostic is generated when a function or its return type is marked with [[nodiscard]] (or __attribute__((warn_unused_result))) and the function call appears as a potentially-evaluated discarded-value expression that is not explicitly cast to void.
You can also tag the returned int
with another tag:
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
[[maybe_unused]] int i = foo ();
}
Could be useful if you have some debug-only code that requires the value.
Cast it to void:
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
static_cast<void>(foo());
}
This basically tells the compiler "Yes I know I'm discarding this, yes I'm sure of it."
I use a (empty) helper function "discard"
template<typename T>
void discard(const T&) {}
[[nodiscard]] int foo ()
{
return 0;
}
int main ()
{
discard(foo());
}
to intentionally discard a [[nodiscard]] value.