Skip to content

Commit f97edda

Browse files
committed
New issue from Arthur O'Dwyer: "sender_concept tags should use _tag, not _t"
1 parent d67149f commit f97edda

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

xml/issue4473.xml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4473" status="New">
5+
<title>`sender_concept` tags should use `_tag`, not `_t`</title>
6+
<section><sref ref="[execution.syn]"/></section>
7+
<submitter>Arthur O'Dwyer</submitter>
8+
<date>12 Nov 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
In November 2025 it was observed that the STL has exactly two places where member typedefs
14+
are used to specify what concepts a type claims to conform to. The first is iterator concept
15+
tags, and the second is sender/receiver concept tags. The former match widespread Boost
16+
practice in using the suffix "`_tag`", e.g.
17+
</p>
18+
<blockquote><pre>
19+
struct forward_iterator_tag {};
20+
using iterator_category = std::forward_iterator_tag;
21+
using iterator_concept = std::forward_iterator_tag;
22+
</pre></blockquote>
23+
<p>
24+
The latter, adopted for C++26, currently use the suffix "_t", e.g.
25+
</p>
26+
<blockquote><pre>
27+
struct sender_t {};
28+
struct receiver_t {};
29+
struct scheduler_t {};
30+
struct operation_state_t {};
31+
using sender_concept = sender_t;
32+
using receiver_concept = receiver_t;
33+
using scheduler_concept = scheduler_t;
34+
using operation_state_concept = operation_state_t;
35+
</pre></blockquote>
36+
<p>
37+
For consistency with the existing STL and with Boost, we should rename each of these four C++26 types:
38+
</p>
39+
<ul>
40+
<li><p>`sender_t` ==> `sender_tag`</p></li>
41+
<li><p>`receiver_t` ==> `receiver_tag`</p></li>
42+
<li><p>`scheduler_t` ==> `scheduler_tag`</p></li>
43+
<li><p>`operation_state_t` ==> `operation_state_tag`</p></li>
44+
</ul>
45+
<p>
46+
Note the distinction between member-typedef "concept tags" like `forward_iterator_tag` and
47+
`execution::sender_t(ag)`, as opposed to "tag constants" used in function signatures like
48+
`defer_lock_t` and `execution::get_allocator_t`.
49+
<p/>
50+
Concept tags:
51+
</p>
52+
<ul>
53+
<li><p>intended for use as member typedefs</p></li>
54+
<li><p>member typedef's name ends in `_category` or `_concept`</p></li>
55+
<li><p>tag type's name ends in `_tag`</p></li>
56+
<li><p>unsuffixed form is a concept, e.g. `concept forward_iterator`, `concept execution::sender`, `concept execution::operation_state`</p></li>
57+
<li><p>always a 1:1 relationship between a tag and a concept</p></li>
58+
<li><p>frequently used as a base class for more tag types</p></li>
59+
</ul>
60+
<p>
61+
Tag constants:
62+
</p>
63+
<ul>
64+
<li><p>never used as member typedefs</p></li>
65+
<li><p>tag type's name ends in `_t`</p></li>
66+
<li><p>unsuffixed form is a constant global variable, e.g. `constexpr auto allocator_arg`, `in_place_type`,
67+
`defer_lock`, `adopt_lock`, `execution::set_value`, `execution::get_allocator`</p></li>
68+
<li><p>never represent a concept</p></li>
69+
<li><p>never used as a base class for more tag types</p></li>
70+
</ul>
71+
<p>
72+
Examples of "concept tags" from outside the STL include these from Boost:
73+
</p>
74+
<ul>
75+
<li><p>Boost.Graph has member typedef `directed_category` corresponding to `directed_tag`, `undirected_tag`, etc.</p></li>
76+
<li><p>Boost.Graph has member typedef `traversal_category` corresponding to `vertex_list_graph_tag`, etc.</p></li>
77+
<li><p>Boost.Fusion has member typedef `fusion_tag` corresponding to `deque_tag`, `vector_tag`, etc.</p></li>
78+
<li><p>Boost.Numeric.Odeint has member typedef `stepper_category` corresponding to `stepper_tag`, etc.</p></li>
79+
<li><p>Boost.Numeric.Ublas has member typedef `dispatch_category` corresponding to `row_major_tag`, `column_major_tag`, etc.</p></li>
80+
<li><p>Boost.Numeric.Ublas has member typedef `type_category` corresponding to `tensor_tag`, etc.</p></li>
81+
<li><p>Boost.Numeric.Ublas has member typedef `storage_category` corresponding to `dense_tag`, `packed_tag`,
82+
`sparse_tag`, etc.</p></li>
83+
</ul>
84+
<p>
85+
A few more examples can be found via GitHub search:
86+
</p>
87+
<ul>
88+
<li><p><a href="https://github.com/search?q=language%3AC%2B%2B+%2F%28%3F-i%29using+.*_concept+%3D+.*_tag%3B%2F+NOT+%2Fitera%3Ftor_concept%2F&amp;type=code">[search-results A]</a></p></li>
89+
<li><p><a href="https://github.com/search?q=language%3AC%2B%2B+%2F%28%3F-i%29using+.*_category+%3D+.*_tag%3B%2F+NOT+%2Fiterator_category%2F&amp;type=code">[search-results B]</a></p></li>
90+
</ul>
91+
<p>
92+
(Notably Jared Hoberock's Croquet, a "prototype implementation of C++ executors, senders, &amp; receivers" from ~2019,
93+
used `sender_tag` in place of `sender_t`.)
94+
<p/>
95+
For consistency with the existing library, we should rename each of these four C++26 types, e.g. `sender_t` to
96+
`sender_tag`... and this needs to be done now, in the C++26 cycle, because it cannot be done later (in which case
97+
we will have failed the community).
98+
</p>
99+
</discussion>
100+
101+
<resolution>
102+
</resolution>
103+
104+
</issue>

0 commit comments

Comments
 (0)