[libcxx-commits] [libcxx] [libc++] Make __is_std_ templates variable templates (PR #150590)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jul 25 01:34:27 PDT 2025
https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/150590
None
>From 8a02a0bfa5660a3916c5d8d22bd84b915cffadd7 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 25 Jul 2025 10:33:58 +0200
Subject: [PATCH] [libc++] Make __is_std_ templates variable templates
---
libcxx/include/__expected/expected.h | 50 +++++++++++++-------------
libcxx/include/__expected/unexpected.h | 17 +++------
libcxx/include/optional | 19 +++++-----
libcxx/include/span | 6 ++--
4 files changed, 41 insertions(+), 51 deletions(-)
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 0f446b870723b..54f9c732e4b33 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -32,6 +32,7 @@
#include <__type_traits/is_reference.h>
#include <__type_traits/is_replaceable.h>
#include <__type_traits/is_same.h>
+#include <__type_traits/is_specialization.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_constructible.h>
#include <__type_traits/is_trivially_destructible.h>
@@ -65,10 +66,7 @@ template <class _Tp, class _Err>
class expected;
template <class _Tp>
-struct __is_std_expected : false_type {};
-
-template <class _Tp, class _Err>
-struct __is_std_expected<expected<_Tp, _Err>> : true_type {};
+concept __is_std_expected_v = __is_specialization_v<_Tp, expected>;
struct __expected_construct_in_place_from_invoke_tag {};
struct __expected_construct_unexpected_from_invoke_tag {};
@@ -450,8 +448,8 @@ class __expected_base {
template <class _Tp, class _Err>
class expected : private __expected_base<_Tp, _Err> {
static_assert(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, in_place_t> &&
- !is_same_v<remove_cv_t<_Tp>, unexpect_t> && !__is_std_unexpected<remove_cv_t<_Tp>>::value &&
- __valid_std_unexpected<_Err>::value,
+ !is_same_v<remove_cv_t<_Tp>, unexpect_t> && !__is_std_unexpected_v<remove_cv_t<_Tp>> &&
+ __is_std_unexpected_v<_Err>,
"[expected.object.general] A program that instantiates the definition of template expected<T, E> for a "
"reference type, a function type, or for possibly cv-qualified types in_place_t, unexpect_t, or a "
"specialization of unexpected for the T parameter is ill-formed. A program that instantiates the "
@@ -557,8 +555,8 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _Up = _Tp>
requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> &&
- is_constructible_v<_Tp, _Up> && !__is_std_unexpected<remove_cvref_t<_Up>>::value &&
- (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value))
+ is_constructible_v<_Tp, _Up> && !__is_std_unexpected_v<remove_cvref_t<_Up>> &&
+ (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected_v<remove_cvref_t<_Up>>))
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>)
expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened
: __base(in_place, std::forward<_Up>(__u)) {}
@@ -670,7 +668,7 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _Up = _Tp>
_LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Up&& __v)
- requires(!is_same_v<expected, remove_cvref_t<_Up>> && !__is_std_unexpected<remove_cvref_t<_Up>>::value &&
+ requires(!is_same_v<expected, remove_cvref_t<_Up>> && !__is_std_unexpected_v<remove_cvref_t<_Up>> &&
is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up> &&
(is_nothrow_constructible_v<_Tp, _Up> || is_nothrow_move_constructible_v<_Tp> ||
is_nothrow_move_constructible_v<_Err>))
@@ -923,7 +921,7 @@ class expected : private __expected_base<_Tp, _Err> {
requires is_constructible_v<_Err, _Err&>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&>>;
- static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Up>, "The result of f(value()) must be a specialization of std::expected");
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(value()) must have the same error_type as this expected");
if (has_value()) {
@@ -936,7 +934,7 @@ class expected : private __expected_base<_Tp, _Err> {
requires is_constructible_v<_Err, const _Err&>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&>>;
- static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Up>, "The result of f(value()) must be a specialization of std::expected");
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(value()) must have the same error_type as this expected");
if (has_value()) {
@@ -950,7 +948,7 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&&>>;
static_assert(
- __is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected");
+ __is_std_expected_v<_Up>, "The result of f(std::move(value())) must be a specialization of std::expected");
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(value())) must have the same error_type as this expected");
if (has_value()) {
@@ -964,7 +962,7 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>;
static_assert(
- __is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected");
+ __is_std_expected_v<_Up>, "The result of f(std::move(value())) must be a specialization of std::expected");
static_assert(is_same_v<typename _Up::error_type, _Err>,
"The result of f(std::move(value())) must have the same error_type as this expected");
if (has_value()) {
@@ -977,7 +975,7 @@ class expected : private __expected_base<_Tp, _Err> {
requires is_constructible_v<_Tp, _Tp&>
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>;
- static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Gp>, "The result of f(error()) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
@@ -990,7 +988,7 @@ class expected : private __expected_base<_Tp, _Err> {
requires is_constructible_v<_Tp, const _Tp&>
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>;
- static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Gp>, "The result of f(error()) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
@@ -1004,7 +1002,7 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>;
static_assert(
- __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
+ __is_std_expected_v<_Gp>, "The result of f(std::move(error())) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
@@ -1018,7 +1016,7 @@ class expected : private __expected_base<_Tp, _Err> {
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>;
static_assert(
- __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
+ __is_std_expected_v<_Gp>, "The result of f(std::move(error())) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
@@ -1166,7 +1164,7 @@ class expected : private __expected_base<_Tp, _Err> {
template <class _T2>
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const _T2& __v)
# if _LIBCPP_STD_VER >= 26
- requires(!__is_std_expected<_T2>::value) && requires {
+ requires(!__is_std_expected_v<_T2>) && requires {
{ *__x == __v } -> __core_convertible_to<bool>;
}
# endif
@@ -1667,7 +1665,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires is_constructible_v<_Err, _Err&>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
- static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Up>, "The result of f() must be a specialization of std::expected");
static_assert(
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
if (has_value()) {
@@ -1680,7 +1678,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires is_constructible_v<_Err, const _Err&>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
- static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Up>, "The result of f() must be a specialization of std::expected");
static_assert(
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
if (has_value()) {
@@ -1693,7 +1691,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires is_constructible_v<_Err, _Err&&>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
- static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Up>, "The result of f() must be a specialization of std::expected");
static_assert(
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
if (has_value()) {
@@ -1706,7 +1704,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
requires is_constructible_v<_Err, const _Err&&>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
- static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Up>, "The result of f() must be a specialization of std::expected");
static_assert(
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
if (has_value()) {
@@ -1718,7 +1716,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>;
- static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Gp>, "The result of f(error()) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
@@ -1730,7 +1728,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>;
- static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
+ static_assert(__is_std_expected_v<_Gp>, "The result of f(error()) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(error()) must have the same value_type as this expected");
if (has_value()) {
@@ -1743,7 +1741,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>;
static_assert(
- __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
+ __is_std_expected_v<_Gp>, "The result of f(std::move(error())) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
@@ -1756,7 +1754,7 @@ class expected<_Tp, _Err> : private __expected_void_base<_Err> {
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>;
static_assert(
- __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
+ __is_std_expected_v<_Gp>, "The result of f(std::move(error())) must be a specialization of std::expected");
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
"The result of f(std::move(error())) must have the same value_type as this expected");
if (has_value()) {
diff --git a/libcxx/include/__expected/unexpected.h b/libcxx/include/__expected/unexpected.h
index 6904889b8c6b1..d642f062fe6a0 100644
--- a/libcxx/include/__expected/unexpected.h
+++ b/libcxx/include/__expected/unexpected.h
@@ -17,6 +17,7 @@
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_object.h>
#include <__type_traits/is_same.h>
+#include <__type_traits/is_specialization.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_volatile.h>
#include <__type_traits/negation.h>
@@ -42,23 +43,15 @@ template <class _Err>
class unexpected;
template <class _Tp>
-struct __is_std_unexpected : false_type {};
-
-template <class _Err>
-struct __is_std_unexpected<unexpected<_Err>> : true_type {};
+concept __is_std_unexpected_v = __is_specialization_v<_Tp, unexpected>;
template <class _Tp>
-using __valid_std_unexpected _LIBCPP_NODEBUG = _BoolConstant< //
- is_object_v<_Tp> && //
- !is_array_v<_Tp> && //
- !__is_std_unexpected<_Tp>::value && //
- !is_const_v<_Tp> && //
- !is_volatile_v<_Tp> //
- >;
+concept __valid_std_unexpected =
+ is_object_v<_Tp> && !is_array_v<_Tp> && !__is_std_unexpected_v<_Tp> && !is_const_v<_Tp> && !is_volatile_v<_Tp>;
template <class _Err>
class unexpected {
- static_assert(__valid_std_unexpected<_Err>::value,
+ static_assert(__valid_std_unexpected<_Err>,
"[expected.un.general] states a program that instantiates std::unexpected for a non-object type, an "
"array type, a specialization of unexpected, or a cv-qualified type is ill-formed.");
diff --git a/libcxx/include/optional b/libcxx/include/optional
index e81bff50daad6..fad1a49506a03 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -214,6 +214,7 @@ namespace std {
# include <__type_traits/is_replaceable.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_scalar.h>
+# include <__type_traits/is_specialization.h>
# include <__type_traits/is_swappable.h>
# include <__type_traits/is_trivially_assignable.h>
# include <__type_traits/is_trivially_constructible.h>
@@ -575,9 +576,7 @@ concept __is_derived_from_optional = requires(const _Tp& __t) { []<class _Up>(co
# endif // _LIBCPP_STD_VER >= 20
template <class _Tp>
-struct __is_std_optional : false_type {};
-template <class _Tp>
-struct __is_std_optional<optional<_Tp>> : true_type {};
+inline constexpr bool __is_std_optional_v = __is_specialization_v<_Tp, optional>;
template <class _Tp>
class _LIBCPP_DECLSPEC_EMPTY_BASES optional
@@ -618,7 +617,7 @@ private:
template <class _Up>
using _CheckOptionalArgsCtor _LIBCPP_NODEBUG =
_If< _IsNotSame<__remove_cvref_t<_Up>, in_place_t>::value && _IsNotSame<__remove_cvref_t<_Up>, optional>::value &&
- (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional<__remove_cvref_t<_Up>>::value),
+ (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional_v<__remove_cvref_t<_Up>>),
_CheckOptionalArgsConstructor,
__check_tuple_constructor_fail >;
template <class _QualUp>
@@ -869,8 +868,8 @@ public:
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
using _Up = invoke_result_t<_Func, value_type&>;
- static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
- "Result of f(value()) must be a specialization of std::optional");
+ static_assert(
+ __is_std_optional_v<remove_cvref_t<_Up>>, "Result of f(value()) must be a specialization of std::optional");
if (*this)
return std::invoke(std::forward<_Func>(__f), value());
return remove_cvref_t<_Up>();
@@ -879,8 +878,8 @@ public:
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
using _Up = invoke_result_t<_Func, const value_type&>;
- static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
- "Result of f(value()) must be a specialization of std::optional");
+ static_assert(
+ __is_std_optional_v<remove_cvref_t<_Up>>, "Result of f(value()) must be a specialization of std::optional");
if (*this)
return std::invoke(std::forward<_Func>(__f), value());
return remove_cvref_t<_Up>();
@@ -889,7 +888,7 @@ public:
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
using _Up = invoke_result_t<_Func, value_type&&>;
- static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
+ static_assert(__is_std_optional_v<remove_cvref_t<_Up>>,
"Result of f(std::move(value())) must be a specialization of std::optional");
if (*this)
return std::invoke(std::forward<_Func>(__f), std::move(value()));
@@ -899,7 +898,7 @@ public:
template <class _Func>
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
using _Up = invoke_result_t<_Func, const value_type&&>;
- static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
+ static_assert(__is_std_optional_v<remove_cvref_t<_Up>>,
"Result of f(std::move(value())) must be a specialization of std::optional");
if (*this)
return std::invoke(std::forward<_Func>(__f), std::move(value()));
diff --git a/libcxx/include/span b/libcxx/include/span
index 3d4f9e4ba7831..718914012c1de 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -203,14 +203,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD
# if _LIBCPP_STD_VER >= 20
template <class _Tp>
-struct __is_std_span : false_type {};
+inline constexpr bool __is_std_span_v = false;
template <class _Tp, size_t _Sz>
-struct __is_std_span<span<_Tp, _Sz>> : true_type {};
+inline constexpr bool __is_std_span_v<span<_Tp, _Sz>> = true;
template <class _Range, class _ElementType>
concept __span_compatible_range =
- !__is_std_span<remove_cvref_t<_Range>>::value && //
+ !__is_std_span_v<remove_cvref_t<_Range>> && //
ranges::contiguous_range<_Range> && //
ranges::sized_range<_Range> && //
(ranges::borrowed_range<_Range> || is_const_v<_ElementType>) && //
More information about the libcxx-commits
mailing list