Skip to content

Commit 731ba81

Browse files
committed
New issue from Jonathan: function<void()> suppresses nodiscard warnings
1 parent 88c18a4 commit 731ba81

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

xml/issue4268.xml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4268" status="New">
5+
<title><code>function&lt;void()&gt;</code> suppresses `nodiscard` warnings</title>
6+
<section><sref ref="[func.require]"/></section>
7+
<submitter>Jonathan Wakely</submitter>
8+
<date>29 May 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<pre><code>struct [[nodiscard]] A { };
13+
A f();
14+
std::function&lt;void()&gt; func = f;
15+
</code></pre>
16+
<p>
17+
Invoking `func()` will discard the return value of `f()`, but there will be
18+
no warning. This is because <code><i>INVOKE</i>&lt;void&gt;(...)</code>
19+
is defined in terms of <code>static_cast&lt;void&gt;(...)</code> and the
20+
explicit cast to void suppresses `nodiscard` warnings.
21+
This is in contast to <code><i>INVOKE</i>&lt;R&gt;(...)</code> where the
22+
conversion to non-void `R` is implicit.
23+
</p>
24+
25+
<p>
26+
It seems right that <code>std::invoke_r&lt;void&gt;(f)</code> should not give
27+
`nodiscard` warnings, because that's quite explicit about converting to void,
28+
and similarly for <code>std::bind&lt;void&gt;(f)()</code>.
29+
However, I think it's debatable whether all uses of <code><i>INVOKE</i>&lt;void&gt;</code> (and <code>std::function&lt;void()&gt;</code> in particular)
30+
intend an explicit cast to void that ignores `nodiscard` types.
31+
It's very easy to set `f` as the target of `func` and then lose its warning,
32+
and there's no explicit use of `void` when you write `func = f; func();`.
33+
</p>
34+
<p>
35+
We could consider defining <code><i>INVOKE</i>&lt;void&gt;(...)</code> to be
36+
an expression of type void, without explicitly saying there's a cast to void.
37+
For example, `(INVOKE(...), void())` would invoke the invocable and have type
38+
`void`, but would not require any `nodiscard` warnings to be suppressed.
39+
If we did that, some uses of <code><i>INVOKE</i>&lt;R&gt;</code> such as
40+
<code>std::invoke_r</code> and <code>std::bind&lt;R&gt;</code> might need to
41+
be adjusted to preserve the explicit conversion to void.
42+
That would allow us to be selective about which uses of
43+
<code><i>INVOKE</i>&lt;void&gt;</code> we consider to be explicit about
44+
discarding results, and which we don't.
45+
</p>
46+
</discussion>
47+
48+
<resolution>
49+
<p>
50+
</p>
51+
</resolution>
52+
53+
</issue>

0 commit comments

Comments
 (0)