Date: Sat, 14 Mar 2026 14:37:03 +0100
On 3/14/26 12:13, Emanuel Spiridon via Std-Proposals wrote:
> C++ currently has no way to create a named and reusable set of types that can be used as a concept constraint. Every time you write a concept constraint or requires section, you must enumerate the types, which makes large constraints unreadable and unmaintainable.
>
> I propose a solution, a type with template arguments for any type, including user-defined types and standard library types, which you can then use when creating a concept or requires section, by stating the named type list and the type you want to check.
>
> Here is how my implementation works:
>
> template<typename T>
> requires std::is_same_v<T, unsigned char> || std::is_same_v<T, unsigned short> || std::is_same_v<T, unsigned int> || std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned long long>
> void natural_only(T);
> template<typename T>
> requires std::is_same_v<T, unsigned char> || std::is_same_v<T, unsigned short> || std::is_same_v<T, unsigned int> || std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned long long> || std::is_same_v<T, char> || std::is_same_v<T, short> || std::is_same_v<T, int> || std::is_same_v<T, long> || std::is_same_v<T, long long>
> void whole_only(T);
>
> using natural_numbers = typename tag::merge_tags_and_types<unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>::type;
> using whole_numbers = typename tag::merge_tags_and_types<signed char, short, int, long, long long, natural_numbers>::type;
> using real_numbers = typename tag::merge_tags_and_types<float, double, long double>::type;
> using numbers = typename tag::merge_tags_and_types<whole_numbers, real_numbers>::type;
I would expect an interface that avoids "typename" and "::type",
e.g. employing an alias template.
> template<typename T>
> concept is_number = tag::contains<numbers, T>;
> template<typename T>
> concept is_whole = tag::contains<whole_numbers, T>;
>
> template<typename T>
> concept is_natural = tag::contains<natural_numbers, T>;
>
> template<typename T>
> concept is_real = tag::contains<real_numbers, T>;
>
> template<typename T>
> requires tag::contains<natural_numbers, T>
> void natural_only(T);
Do we get subsumption, i.e.
f(is_real auto)
is more specialized than
f(is_number auto)
?
If not, that feels like causing a bad bang-for-the-buck ratio
of this facility.
Jens
> C++ currently has no way to create a named and reusable set of types that can be used as a concept constraint. Every time you write a concept constraint or requires section, you must enumerate the types, which makes large constraints unreadable and unmaintainable.
>
> I propose a solution, a type with template arguments for any type, including user-defined types and standard library types, which you can then use when creating a concept or requires section, by stating the named type list and the type you want to check.
>
> Here is how my implementation works:
>
> template<typename T>
> requires std::is_same_v<T, unsigned char> || std::is_same_v<T, unsigned short> || std::is_same_v<T, unsigned int> || std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned long long>
> void natural_only(T);
> template<typename T>
> requires std::is_same_v<T, unsigned char> || std::is_same_v<T, unsigned short> || std::is_same_v<T, unsigned int> || std::is_same_v<T, unsigned long> || std::is_same_v<T, unsigned long long> || std::is_same_v<T, char> || std::is_same_v<T, short> || std::is_same_v<T, int> || std::is_same_v<T, long> || std::is_same_v<T, long long>
> void whole_only(T);
>
> using natural_numbers = typename tag::merge_tags_and_types<unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>::type;
> using whole_numbers = typename tag::merge_tags_and_types<signed char, short, int, long, long long, natural_numbers>::type;
> using real_numbers = typename tag::merge_tags_and_types<float, double, long double>::type;
> using numbers = typename tag::merge_tags_and_types<whole_numbers, real_numbers>::type;
I would expect an interface that avoids "typename" and "::type",
e.g. employing an alias template.
> template<typename T>
> concept is_number = tag::contains<numbers, T>;
> template<typename T>
> concept is_whole = tag::contains<whole_numbers, T>;
>
> template<typename T>
> concept is_natural = tag::contains<natural_numbers, T>;
>
> template<typename T>
> concept is_real = tag::contains<real_numbers, T>;
>
> template<typename T>
> requires tag::contains<natural_numbers, T>
> void natural_only(T);
Do we get subsumption, i.e.
f(is_real auto)
is more specialized than
f(is_number auto)
?
If not, that feels like causing a bad bang-for-the-buck ratio
of this facility.
Jens
Received on 2026-03-14 13:37:06
