Title
function<void()> suppresses `nodiscard` warnings
Status
new
Section
[func.require]
Submitter
Jonathan Wakely

Created on 2025-05-29.00:00:00 last changed 3 weeks ago

Messages

Date: 2025-05-29.00:00:00
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.

History
Date User Action Args
2025-05-29 00:00:00admincreate