Skip to content

Commit 080a54d

Browse files
committed
New issue from Jonathan: Stream insertion for chrono::local_time should be constrained
1 parent b33fc92 commit 080a54d

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

xml/issue4257.xml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4257" status="New">
5+
<title>Stream insertion for `chrono::local_time` should be constrained</title>
6+
<section><sref ref="[time.clock.local]"/></section>
7+
<submitter>Jonathan Wakely</submitter>
8+
<date>16 May 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
Stream insertion for `chrono::local_time` is defined in terms of conversion to
14+
`chrono::sys_time`, but not all `chrono::sys_time` specializations
15+
can be inserted into an ostream, because one of the overloads is
16+
constrained and the other requires convertibility to `chrono::sys_days`
17+
(see <sref ref="[time.clock.system.nonmembers]"/>).
18+
</p>
19+
<p>
20+
This means the following code fails to compile:
21+
<pre><code>
22+
#include &lt;iostream&gt;
23+
#include &lt;chrono&gt;
24+
25+
template&lt;typename T&gt;
26+
concept ostream_insertable = requires (std::ostream&amp; o, const T&amp; t) { o &lt;&lt; t; };
27+
28+
using D = std::chrono::duration&lt;double&gt;;
29+
30+
int main() {
31+
if constexpr (ostream_insertable&lt;std::chrono::sys_time&lt;D&gt;&gt;)
32+
std::cout &lt;&lt; std::chrono::sys_time&lt;D&gt;{};
33+
if constexpr (ostream_insertable&lt;std::chrono::local_time&lt;D&gt;&gt;)
34+
std::cout &lt;&lt; std::chrono::local_time&lt;D&gt;{}; // <b>FAIL</b>
35+
}
36+
</code></pre>
37+
The first condition is false, because there's no overload that's suitable.
38+
The second is true, because the <code>operator&lt;&lt;</code> overload for
39+
`chrono::local_time` isn't constrained and so insertion appears to be valid.
40+
But actually trying to use it is ill-formed, because it tries to convert the
41+
<code>local_time&lt;D&gt;</code> to a <code>sys_time&lt;D&gt;</code>
42+
and then insert that, which isn't valid.
43+
</p>
44+
</discussion>
45+
46+
<resolution>
47+
<p>
48+
This wording is relative to <paper num="N5008"/>.
49+
</p>
50+
51+
<ol>
52+
<li><p>Modify <sref ref="[time.clock.local]"/> as indicated:</p>
53+
54+
<blockquote>
55+
<pre><code>
56+
template&lt;class charT, class traits, class Duration&gt;
57+
basic_ostream&lt;charT, traits&gt;&amp;
58+
operator&lt;&lt;(basic_ostream&lt;charT, traits&gt;&amp; os, const local_time&lt;Duration&gt;&amp; lt);
59+
</code></pre>
60+
<p><ins>-?- <i>Constraints</i>:
61+
<code>os &lt;&lt; sys_time&lt;Duration&gt;{lt.time_since_epoch()}</code>
62+
is a valid expression.</ins>
63+
</p>
64+
<p>-2- <i>Effects</i>:
65+
<pre><code> os &lt;&lt; sys_time&lt;Duration&gt;{lt.time_since_epoch()};
66+
</code></pre>
67+
</p>
68+
<p>-3- <i>Returns</i>: `os`.</p>
69+
</blockquote>
70+
</li>
71+
</ol>
72+
73+
</resolution>
74+
75+
</issue>

0 commit comments

Comments
 (0)