Date: Mon, 10 Nov 2025 13:46:35 -0500
On Mon, Nov 10, 2025 at 1:06 PM Jonathan Wakely <cxx_at_[hidden]> wrote:
> On Mon, 10 Nov 2025, 15:51 Arthur O'Dwyer via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
>> On Mon, Nov 10, 2025 at 1:15 AM 叶易安 via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> We notice that we have 2 available 'tags' in C++ standard library now:
>>>
>>> =====
>>> class my_iterator { using iterator_concept =
>>> std::random_access_iterator_tag };
>>> class my_sender { using sender_concept = std::execution::sender_t; }
>>> =====
>>>
>>> Oops, the first ends with `_tag` and the second ends with `_t`. But they
>>> share the same effect (to make a class satisfy a particular concept).
>>> Should we unify them?
>>> Hmmm, before that let's see where we use `_tag` and `_t` in C++ standard
>>> library.
>>>
>>> xxx_t:
>>> 1. <type_traits>. When we have `add_const<T>::type`, we typedef an
>>> `add_const_t<T>`.
>>> 2. Typedef which unifies different platforms. `uint8_t`, `wchar_t`,
>>> `clock_t`, etc.
>>> 3. Utility type of global constexpr variable. e.g. nullopt_t,
>>> unexpected_t, etc.
>>> 4. Utility type of function overload parameters. e.g.
>>> unique_lock(defer_lock_t), vector(from_range_t), etc.
>>>
>>> xxx_tag:
>>> 1. Customize xxx_concept in class. e.g. using iterator_concept
>>> forward/bidirectional/.../random_access_iterator_tag.
>>>
>>> Should we rename `std::execution::sender_t` into
>>> `std::execution::sender_tag`?
>>> Thank you!
>>>
>>
>> Yes, it certainly seems so (at first glance) to me. Like you, I'm not
>> aware of any prior art for using `_t` as the suffix for a tag type.
>>
>
> Aren't allocator_arg_t, inplace_t, defer_lock_t etc. tag types?
>
Not in the same sense. Those are the kind of tag type where we write
namespace std { struct foo_t {}; constexpr foo_t foo; }
usercode(std::foo, ...);
sender_t and receiver_t and foo_iterator_tag are the kind of tag type where
we write
namespace std { struct foo_tag {}; }
struct Usercode { using foo_concept = std::foo_tag; };
We do indeed have the same kind of overloaded-English-word problem with
"tag type" that we have with "traits class," but it's true that sender_t
and receiver_t are the same kind as foo_iterator_tag and not at all the
same kind as allocator_arg_t, inplace_t, inplace_type_t, defer_lock_t,
adopt_lock_t, etc. Nor are they the same kind as std::nullopt_t, nor
std::monostate.
Using a "tag" suffix is unique to the iterator categories, which are from
> 30 years ago and that design hasn't been repeated elsewhere in the library.
>
But that's precisely because no other place in the library has repeated the
using foo_category = ...;
using foo_concept = ...;
design, before now, isn't it? AFAIR the closest we've ever come between
C++98's iterator concept tags and C++26 S/R concept tags is the (IMO
ill-advised)
using is_transparent = void;
which didn't introduce any new tag types.
–Arthur
> On Mon, 10 Nov 2025, 15:51 Arthur O'Dwyer via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
>> On Mon, Nov 10, 2025 at 1:15 AM 叶易安 via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> We notice that we have 2 available 'tags' in C++ standard library now:
>>>
>>> =====
>>> class my_iterator { using iterator_concept =
>>> std::random_access_iterator_tag };
>>> class my_sender { using sender_concept = std::execution::sender_t; }
>>> =====
>>>
>>> Oops, the first ends with `_tag` and the second ends with `_t`. But they
>>> share the same effect (to make a class satisfy a particular concept).
>>> Should we unify them?
>>> Hmmm, before that let's see where we use `_tag` and `_t` in C++ standard
>>> library.
>>>
>>> xxx_t:
>>> 1. <type_traits>. When we have `add_const<T>::type`, we typedef an
>>> `add_const_t<T>`.
>>> 2. Typedef which unifies different platforms. `uint8_t`, `wchar_t`,
>>> `clock_t`, etc.
>>> 3. Utility type of global constexpr variable. e.g. nullopt_t,
>>> unexpected_t, etc.
>>> 4. Utility type of function overload parameters. e.g.
>>> unique_lock(defer_lock_t), vector(from_range_t), etc.
>>>
>>> xxx_tag:
>>> 1. Customize xxx_concept in class. e.g. using iterator_concept
>>> forward/bidirectional/.../random_access_iterator_tag.
>>>
>>> Should we rename `std::execution::sender_t` into
>>> `std::execution::sender_tag`?
>>> Thank you!
>>>
>>
>> Yes, it certainly seems so (at first glance) to me. Like you, I'm not
>> aware of any prior art for using `_t` as the suffix for a tag type.
>>
>
> Aren't allocator_arg_t, inplace_t, defer_lock_t etc. tag types?
>
Not in the same sense. Those are the kind of tag type where we write
namespace std { struct foo_t {}; constexpr foo_t foo; }
usercode(std::foo, ...);
sender_t and receiver_t and foo_iterator_tag are the kind of tag type where
we write
namespace std { struct foo_tag {}; }
struct Usercode { using foo_concept = std::foo_tag; };
We do indeed have the same kind of overloaded-English-word problem with
"tag type" that we have with "traits class," but it's true that sender_t
and receiver_t are the same kind as foo_iterator_tag and not at all the
same kind as allocator_arg_t, inplace_t, inplace_type_t, defer_lock_t,
adopt_lock_t, etc. Nor are they the same kind as std::nullopt_t, nor
std::monostate.
Using a "tag" suffix is unique to the iterator categories, which are from
> 30 years ago and that design hasn't been repeated elsewhere in the library.
>
But that's precisely because no other place in the library has repeated the
using foo_category = ...;
using foo_concept = ...;
design, before now, isn't it? AFAIR the closest we've ever come between
C++98's iterator concept tags and C++26 S/R concept tags is the (IMO
ill-advised)
using is_transparent = void;
which didn't introduce any new tag types.
–Arthur
Received on 2025-11-10 18:46:50
