function<void()> suppresses nodiscard warningsSection: 22.10.4 [func.require] Status: New Submitter: Jonathan Wakely Opened: 2025-05-29 Last modified: 2025-05-29
Priority: Not Prioritized
View other active issues in [func.require].
View all other issues in [func.require].
View all issues with New status.
Discussion:
struct [[nodiscard]] A { };
A f();
std::function<void()> func = f;
Invoking func() will discard the return value of f(), but there will be
no warning. This is because INVOKE<void>(...)
is defined in terms of static_cast<void>(...) and the
explicit cast to void suppresses nodiscard warnings.
This is in contast to INVOKE<R>(...) where the
conversion to non-void R is implicit.
It seems right that std::invoke_r<void>(f) should not give
nodiscard warnings, because that's quite explicit about converting to void,
and similarly for std::bind<void>(f)().
However, I think it's debatable whether all uses of INVOKE<void> (and std::function<void()> in particular)
intend an explicit cast to void that ignores nodiscard types.
It's very easy to set f as the target of func and then lose its warning,
and there's no explicit use of void when you write func = f; func();.
We could consider defining INVOKE<void>(...) to be
an expression of type void, without explicitly saying there's a cast to void.
For example, (INVOKE(...), void()) would invoke the invocable and have type
void, but would not require any nodiscard warnings to be suppressed.
If we did that, some uses of INVOKE<R> such as
std::invoke_r and std::bind<R> might need to
be adjusted to preserve the explicit conversion to void.
That would allow us to be selective about which uses of
INVOKE<void> we consider to be explicit about
discarding results, and which we don't.
Proposed resolution: