From 5170095ad0addffd9afe54c6f9f7f2c6fe2e1137 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:33:40 +0900 Subject: [PATCH 1/9] Fix boolean_testable --- include/preview/__concepts/boolean_testable.h | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/include/preview/__concepts/boolean_testable.h b/include/preview/__concepts/boolean_testable.h index ebb31e87..f75f23e8 100644 --- a/include/preview/__concepts/boolean_testable.h +++ b/include/preview/__concepts/boolean_testable.h @@ -14,44 +14,29 @@ namespace preview { namespace detail { -template -struct boolean_testable_impl : convertible_to {}; +template +struct boolean_testable_impl : convertible_to {}; template struct is_explicitly_negatable : std::false_type {}; template struct is_explicitly_negatable())> > : std::true_type {}; -template< - typename B, - bool = - conjunction< - is_explicitly_negatable>>, - is_explicitly_negatable>> - >::value -> +template::value> struct boolean_testable_stage_2 : std::false_type {}; +template +struct boolean_testable_stage_2 : boolean_testable_impl())> {}; -template -struct boolean_testable_stage_2 - : conjunction< - boolean_testable_impl> >())>, - boolean_testable_impl> >())> - > {}; - -template< - typename B, - bool = conjunction, is_referencable>::value -> +template::value> struct boolean_testable_stage_1 : std::false_type {}; - -template -struct boolean_testable_stage_1 : boolean_testable_stage_2 {}; +template +struct boolean_testable_stage_1 : boolean_testable_stage_2 {}; } // namespace detail -template -struct boolean_testable : detail::boolean_testable_stage_1 {}; +// TODO: concept +template +struct boolean_testable : detail::boolean_testable_stage_1 {}; } // namespace preview From 7ef0abb8ca4a21b4fbc3f4a01a624637d4e9344b Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:33:57 +0900 Subject: [PATCH 2/9] Update addressof.h --- include/preview/__memory/addressof.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/preview/__memory/addressof.h b/include/preview/__memory/addressof.h index 12ba63b0..2d1a05e4 100644 --- a/include/preview/__memory/addressof.h +++ b/include/preview/__memory/addressof.h @@ -18,10 +18,10 @@ namespace detail { PREVIEW_INLINE_VARIABLE constexpr int builtin_addressof_tester{}; template -struct have_builtin_addressof : std::false_type {}; +struct have_builtin_addressof_test : std::false_type {}; template<> -struct have_builtin_addressof< +struct have_builtin_addressof_test< void_t< decltype(std::integral_constant< bool, @@ -30,6 +30,8 @@ struct have_builtin_addressof< > > : std::true_type {}; +using have_builtin_addressof = have_builtin_addressof_test<>; + template constexpr T* addressof_object(T& t, std::true_type) noexcept { return __builtin_addressof(t); @@ -46,7 +48,7 @@ T* addressof_object(T& t, std::false_type) noexcept { template constexpr T* addressof_impl(T& t, std::true_type /* is_object */) noexcept { - return preview::detail::addressof_object(t, have_builtin_addressof<>{}); + return preview::detail::addressof_object(t, have_builtin_addressof{}); } template From e14d38d9467badba358310dcd9e8168870f9c4ea Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:34:31 +0900 Subject: [PATCH 3/9] Create synth_three_way.h --- include/preview/__compare/synth_three_way.h | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 include/preview/__compare/synth_three_way.h diff --git a/include/preview/__compare/synth_three_way.h b/include/preview/__compare/synth_three_way.h new file mode 100644 index 00000000..03db7204 --- /dev/null +++ b/include/preview/__compare/synth_three_way.h @@ -0,0 +1,35 @@ +// +// Created by yonggyulee on 2024. 10. 17. +// + +#ifndef PREVIEW_COMPARE_SYNTH_THREE_WAY_H_ +#define PREVIEW_COMPARE_SYNTH_THREE_WAY_H_ + +#include + +#include "preview/__concepts/boolean_testable.h" +#include "preview/__type_traits/conjunction.h" +#include "preview/__utility/cxx20_rel_ops.h" + +namespace preview { +namespace detail { + +template, + rel_ops::is_less_equal_than_comparable + > +> +struct synth_three_way_possible : std::false_type {}; + +template +struct synth_three_way_possible + : conjunction< + boolean_testable() < std::declval())>, + boolean_testable() < std::declval())> + > {}; + +} // namespace detail +} // namespace preview + +#endif // PREVIEW_COMPARE_SYNTH_THREE_WAY_H_ From fbc2c9a73ac3822afb47415b57eb07747a0462ce Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:34:51 +0900 Subject: [PATCH 4/9] Create is_reference_wrapper.h --- .../__functional/is_reference_wrapper.h | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 include/preview/__functional/is_reference_wrapper.h diff --git a/include/preview/__functional/is_reference_wrapper.h b/include/preview/__functional/is_reference_wrapper.h new file mode 100644 index 00000000..a68e5187 --- /dev/null +++ b/include/preview/__functional/is_reference_wrapper.h @@ -0,0 +1,21 @@ +// +// Created by yonggyulee on 2024. 10. 17. +// + +#ifndef PREVIEW_FUNCTIONAL_IS_REFERENCE_WRAPPER_H_ +#define PREVIEW_FUNCTIONAL_IS_REFERENCE_WRAPPER_H_ + +#include +#include + +namespace preview { + +template +struct is_reference_wrapper : std::false_type {}; + +template +struct is_reference_wrapper> : std::true_type {}; + +} // namespace preview + +#endif // PREVIEW_FUNCTIONAL_IS_REFERENCE_WRAPPER_H_ From f584851e46681ca40dc4fed110c5c3f910400704 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:35:41 +0900 Subject: [PATCH 5/9] Update invoke for reference_wrapper --- include/preview/__type_traits/detail/invoke.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/preview/__type_traits/detail/invoke.h b/include/preview/__type_traits/detail/invoke.h index 6da69696..cf69b4b7 100644 --- a/include/preview/__type_traits/detail/invoke.h +++ b/include/preview/__type_traits/detail/invoke.h @@ -9,7 +9,7 @@ #include #include -#include "preview/__type_traits/is_specialization.h" +#include "preview/__functional/is_reference_wrapper.h" #include "preview/__type_traits/remove_cvref.h" namespace preview { @@ -114,7 +114,7 @@ struct get_invoke_tag_1 : std::integral_constant>::value, - bool v2 = is_specialization, std::reference_wrapper>::value> + bool v2 = is_reference_wrapper>::value> struct get_invoke_tag_2; template From c0003c7d05a7c3b9602982937bb583623a820059 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:36:13 +0900 Subject: [PATCH 6/9] Fix common_reference for reference_wrapper types --- .../__type_traits/basic_common_reference.h | 135 ++++++------------ ...sic_common_reference_std_specializations.h | 126 ++++++++++++++++ .../preview/__type_traits/common_reference.h | 7 +- 3 files changed, 176 insertions(+), 92 deletions(-) create mode 100644 include/preview/__type_traits/basic_common_reference_std_specializations.h diff --git a/include/preview/__type_traits/basic_common_reference.h b/include/preview/__type_traits/basic_common_reference.h index 52bab0ec..4266d9b6 100644 --- a/include/preview/__type_traits/basic_common_reference.h +++ b/include/preview/__type_traits/basic_common_reference.h @@ -5,116 +5,75 @@ #ifndef PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_H_ #define PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_H_ -#include +#include +#include "preview/__core/inline_variable.h" +#include "preview/__functional/is_reference_wrapper.h" #include "preview/__tuple/tuple_like.h" #include "preview/__type_traits/bool_constant.h" -#include "preview/__type_traits/common_reference.h" +#include "preview/__type_traits/conditional.h" +#include "preview/__type_traits/conjunction.h" +#include "preview/__type_traits/detail/tag.h" #include "preview/__type_traits/disjunction.h" -#include "preview/__type_traits/is_specialization.h" -#include "preview/__type_traits/negation.h" -#include "preview/__type_traits/no_traits.h" -#include "preview/__type_traits/type_identity.h" namespace preview { namespace detail { - -template class TQual, template class UQual, - bool = conjunction, tuple_like>::value /* false */> -struct basic_common_reference_tuple_like : no_traits {}; - -template class TQual, template class UQual, typename Index> -struct basic_common_reference_tuple_like_impl_2; - -template class TQual, template class UQual, std::size_t... I> -struct basic_common_reference_tuple_like_impl_2> { - using type = std::tuple< - common_reference_t< - TQual< std::tuple_element_t >, - UQual< std::tuple_element_t > - >... >; +namespace bcr_specialization { + +// TODO: Concept +// true specialization is defined in basic_common_reference_std_specializations.h +template::value> +struct ref_wrap_common_reference_exists_with : std::false_type {}; + +enum category_t : int { + kDefault = 0, + kTupleLike = 1, + kPair = 2, + kReferenceWrapper = 3, }; -template class TQual, template class UQual, typename Index> -struct basic_common_reference_tuple_like_impl_1; - -template class TQual, template class UQual, std::size_t... I> -struct basic_common_reference_tuple_like_impl_1> - : std::conditional_t< - conjunction< - has_typename_type< common_reference>, - UQual>> >... - >::value, - basic_common_reference_tuple_like_impl_2>, - no_traits - > {}; +template class TQual, template class UQual, + bool SatisfyRequires = /* false */ conjunction_v, tuple_like>> +struct satisfy_tuple_like_constraints : std::false_type {}; +template class TQual, template class UQual> +struct satisfy_pair_constraints : std::false_type {}; -template class TQual, template class UQual> -struct basic_common_reference_tuple_like - : std::conditional_t< - conjunction< - disjunction< is_specialization, is_specialization >, - std::is_same>, - std::is_same>, - bool_constant<(std::tuple_size>::value == std::tuple_size>::value)> - >::value, - basic_common_reference_tuple_like_impl_1>::value>>, - no_traits - > {}; +template class TQual, template class UQual, + bool SatisfyRequires = /* false */( + (ref_wrap_common_reference_exists_with, UQual>::value && + !ref_wrap_common_reference_exists_with, TQual>::value) || + (ref_wrap_common_reference_exists_with, TQual>::value && + !ref_wrap_common_reference_exists_with, UQual>::value) + )> +struct satisfy_ref_wrap_constraints : bool_constant {}; -template class TQual, template class UQual, bool /* false */> -struct basic_common_reference_pair {}; +template class TQual, template class UQual> +PREVIEW_INLINE_VARIABLE constexpr int category = preview::conditional_t< + satisfy_tuple_like_constraints , tag_v, + satisfy_pair_constraints , tag_v, + satisfy_ref_wrap_constraints , tag_v, + tag_v +>::value; -template class TQual, template class UQual> -struct basic_common_reference_pair, std::pair, TQual, UQual, true> { - using type = std::pair< common_reference_t, UQual>, - common_reference_t, UQual> >; -}; +template class TQual, template class UQual, int Tag> +struct basic_common_reference_base; -template >, - has_typename_type< common_reference > - >::value /* false */> -struct basic_common_reference_ref_wrap {}; - -template -struct basic_common_reference_ref_wrap - : std::conditional_t< - convertible_to>::value, - type_identity>, - no_traits - > {}; +template class TQual, template class UQual> +struct basic_common_reference_base {}; +} // namespace bcr_specialization } // namespace detail // Primary template template class TQual, template class UQual> -struct basic_common_reference : detail::basic_common_reference_tuple_like {}; - -// specializations of basic_common_reference -template class TQual, template class UQual> -struct basic_common_reference, std::pair, TQual, UQual> - : detail::basic_common_reference_pair< - std::pair, std::pair, +struct basic_common_reference + : detail::bcr_specialization::basic_common_reference_base< + T, U, TQual, UQual, - conjunction< - has_typename_type< common_reference< TQual, UQual > >, - has_typename_type< common_reference< TQual, UQual > > - >::value + detail::bcr_specialization::category > {}; -template class RQual, template class TQual> -struct basic_common_reference, T, RQual, TQual> - : detail::basic_common_reference_ref_wrap, TQual> {}; - -template class RQual, template class TQual> -struct basic_common_reference, TQual, RQual> - : detail::basic_common_reference_ref_wrap, TQual> {}; - - } // namespace preview #endif // PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_H_ diff --git a/include/preview/__type_traits/basic_common_reference_std_specializations.h b/include/preview/__type_traits/basic_common_reference_std_specializations.h new file mode 100644 index 00000000..f2fcb893 --- /dev/null +++ b/include/preview/__type_traits/basic_common_reference_std_specializations.h @@ -0,0 +1,126 @@ +// +// Created by yonggyulee on 2024. 10. 17. +// + +#ifndef PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_STD_SPECIALIZATIONS_H_ +#define PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_STD_SPECIALIZATIONS_H_ + +#include +#include +#include + +#include "preview/__concepts/convertible_to.h" +#include "preview/__tuple/tuple_like.h" +#include "preview/__tuple/tuple_integer_sequence.h" +#include "preview/__type_traits/basic_common_reference.h" +#include "preview/__type_traits/common_reference.h" +#include "preview/__type_traits/disjunction.h" +#include "preview/__type_traits/has_typename_type.h" +#include "preview/__type_traits/is_specialization.h" + +namespace preview { +namespace detail { +namespace bcr_specialization { + +// basic_common_reference + +template class TQual, template class UQual, typename IndexSequence> +struct satisfy_tuple_like_constraints_impl_3; +template class TQual, template class UQual, std::size_t... I> +struct satisfy_tuple_like_constraints_impl_3> : conjunction< + has_typename_type< + common_reference>, + UQual>> + >... +> {}; + +template class TQual, template class UQual, + bool = /* false */ (std::tuple_size::value == std::tuple_size::value)> +struct satisfy_tuple_like_constraints_impl_2 : std::false_type {}; + +template class TQual, template class UQual> +struct satisfy_tuple_like_constraints_impl_2 + : satisfy_tuple_like_constraints_impl_3> {}; + +template class TQual, template class UQual, + bool = /* false */ conjunction_v< + disjunction, is_specialization>, + std::is_same>, + std::is_same> + > +> +struct satisfy_tuple_like_constraints_impl : std::false_type {}; + +template class TQual, template class UQual> +struct satisfy_tuple_like_constraints_impl + : satisfy_tuple_like_constraints_impl_2 {}; + +template class TQual, template class UQual> +struct satisfy_tuple_like_constraints + : satisfy_tuple_like_constraints_impl {}; + +template class TQual, template class UQual, typename ISeq> +struct basic_common_reference_base_tuple_like; + +template class TQual, template class UQual, std::size_t... I> +struct basic_common_reference_base_tuple_like> { + using type = std::tuple< + common_reference_t, + std::tuple_element_t> + ... + >; +}; + +template class TQual, template class UQual> +struct basic_common_reference_base + : basic_common_reference_base_tuple_like> {}; + + + +// basic_const_reference + +template class TQual, template class UQual> +struct satisfy_pair_constraints, std::pair, TQual, UQual> : conjunction< + has_typename_type, UQual>>, + has_typename_type, UQual>> +> {}; + +template class TQual, template class UQual> +struct basic_common_reference_base, std::pair, TQual, UQual, kPair> { + using type = std::pair, common_reference_t>; +}; + + + +// basic_const_reference +// basic_const_reference + +template>::value> +struct ref_wrap_common_reference_exists_with_impl : std::false_type {}; + +template +struct ref_wrap_common_reference_exists_with_impl + : convertible_to> {}; + +template +struct ref_wrap_common_reference_exists_with + : ref_wrap_common_reference_exists_with_impl {}; + +template class RQual, template class TQual> +struct basic_common_reference_ref_wrap { + using type = common_reference_t>; +}; + +template class TQual, template class UQual> +struct basic_common_reference_base : std::conditional_t< + (ref_wrap_common_reference_exists_with, UQual>::value && + !ref_wrap_common_reference_exists_with, TQual>::value), + basic_common_reference_ref_wrap, + basic_common_reference_ref_wrap +> {}; + +} // namespace bcr_specialization +} // namespace detail +} // namespace preview + +#endif // PREVIEW_TYPE_TRAITS_BASIC_COMMON_REFERENCE_STD_SPECIALIZATIONS_H_ diff --git a/include/preview/__type_traits/common_reference.h b/include/preview/__type_traits/common_reference.h index bf167e1f..f710d4b3 100644 --- a/include/preview/__type_traits/common_reference.h +++ b/include/preview/__type_traits/common_reference.h @@ -10,6 +10,7 @@ #include #include "preview/__concepts/convertible_to.h" +#include "preview/__type_traits/basic_common_reference.h" #include "preview/__type_traits/conjunction.h" #include "preview/__type_traits/common_type.h" #include "preview/__type_traits/copy_cvref.h" @@ -20,10 +21,6 @@ namespace preview { -// forward declare -template class TQual, template class UQual> -struct basic_common_reference; - template struct common_reference; @@ -155,4 +152,6 @@ using common_reference_t = typename common_reference::type; } // namespace preview +#include "preview/__type_traits/basic_common_reference_std_specializations.h" + #endif // PREVIEW_TYPE_TRAITS_COMMON_REFERENCE_H_ From 5301254b98f8fd8129547c947c9ed7eff105c5ff Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 00:36:29 +0900 Subject: [PATCH 7/9] Implement C++26 reference_wrapper --- .../preview/__functional/reference_wrapper.h | 349 ++++++++++++++++++ include/preview/__ranges/ref_view.h | 16 +- .../preview/__type_traits/unwrap_reference.h | 7 + include/preview/functional.h | 1 + 4 files changed, 359 insertions(+), 14 deletions(-) create mode 100644 include/preview/__functional/reference_wrapper.h diff --git a/include/preview/__functional/reference_wrapper.h b/include/preview/__functional/reference_wrapper.h new file mode 100644 index 00000000..e2196eef --- /dev/null +++ b/include/preview/__functional/reference_wrapper.h @@ -0,0 +1,349 @@ +// +// Created by yonggyulee on 2024. 10. 14. +// + +#ifndef PREVIEW_FUNCTIONAL_REFERENCE_WRAPPER_H_ +#define PREVIEW_FUNCTIONAL_REFERENCE_WRAPPER_H_ + +#include +#include +#include + +#include "preview/config.h" +#include "preview/__core/std_version.h" +#include "preview/__compare/synth_three_way.h" +#include "preview/__functional/is_reference_wrapper.h" +#include "preview/__memory/addressof.h" +#include "preview/__type_traits/detail/invoke.h" +#include "preview/__type_traits/basic_common_reference.h" +#include "preview/__type_traits/bool_constant.h" +#include "preview/__type_traits/conjunction.h" +#include "preview/__type_traits/common_reference.h" +#include "preview/__type_traits/is_complete.h" +#include "preview/__type_traits/is_invocable.h" +#include "preview/__type_traits/negation.h" +#include "preview/__type_traits/remove_cvref.h" +#include "preview/__utility/in_place.h" +#include "preview/__utility/cxx20_rel_ops.h" + +#if PREVIEW_CONFORM_CXX20_STANDARD +#include +#endif + +namespace preview { +namespace detail { + +struct can_bind_to_reference_helper { + template + static void FUN(T&) noexcept; + +#if defined(_MSC_VER) && _MSC_VER < 1920 + template::value, int> = 0> + static auto FUN(T&&) -> void; +#else + template + static void FUN(T&&) = delete; +#endif + + template + static auto test(int) -> decltype(FUN(std::declval()), std::true_type{}); + template + static auto test(...) -> std::false_type; +}; + +template +struct can_bind_to_reference : decltype(can_bind_to_reference_helper::test(0)) {}; +template +struct can_bind_to_reference_noexcept : bool_constant(std::declval()))> {}; + +} // namespace detail + +template +class reference_wrapper { + public: + using type = T; + + template, + negation< std::is_same, preview::reference_wrapper> >, + negation< std::is_same, std::reference_wrapper> > + >::value, int> = 0> + constexpr reference_wrapper(U&& u) + noexcept(detail::can_bind_to_reference_noexcept::value) + : reference_wrapper(in_place, std::forward(u)) {} + + constexpr reference_wrapper(const reference_wrapper& x) noexcept + : ptr_(x.ptr_) {} + constexpr reference_wrapper& operator=(const reference_wrapper& x) noexcept = default; + + constexpr reference_wrapper(std::reference_wrapper x) noexcept + : reference_wrapper(in_place, x.get()) {} + constexpr reference_wrapper& operator=(std::reference_wrapper x) noexcept { + ptr_ = preview::addressof(x.get()); + } + + constexpr operator T& () const noexcept { + return *ptr_; + } + + constexpr T& get() const noexcept { + return *ptr_; + } + + // Not a standard function! This is required for std::invoke to handle reference_wrapper correctly. + constexpr T& operator*() const noexcept { + return *ptr_; + } + + // Not a standard function! Use this function on deduced context is needed + std::reference_wrapper to_std() { + return get(); + } + + template + constexpr invoke_result_t + operator()(ArgTypes&&... args) const noexcept(is_nothrow_invocable::value) { + static_assert(is_complete_v, "T must be complete type"); + return preview::detail::INVOKE(get(), std::forward(args)...); + } + + template::value, int> = 0> + friend constexpr bool operator==(reference_wrapper x, reference_wrapper y) { + return x.get() == y.get(); + } +#if !PREVIEW_CONFORM_CXX20_STANDARD + template::value, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, reference_wrapper y) { + return !(x == y); + } +#endif + + template::value, int> = 0> + friend constexpr bool operator==(reference_wrapper x, const T& y) { + return x.get() == y; + } +#if !PREVIEW_CONFORM_CXX20_STANDARD + template::value, int> = 0> + friend constexpr bool operator==(const T& y, reference_wrapper x) { + return x == y; + } + template::value, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, const T& y) { + return !(x == y); + } + template::value, int> = 0> + friend constexpr bool operator!=(const T& y, reference_wrapper x) { + return !(x == y); + } +#endif + + // T == const T + template>, rel_ops::is_equality_comparable>, int> = 0> + friend constexpr bool operator==(reference_wrapper x, reference_wrapper y) { + return x.get() == y.get(); + } +#if !PREVIEW_CONFORM_CXX20_STANDARD + // T != const T + template>, rel_ops::is_equality_comparable>, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, reference_wrapper y) { + return !(x == y); + } + // const T == T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator==(reference_wrapper x, reference_wrapper> y) { + return y.get() == x.get(); + } + // const T != T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, reference_wrapper> y) { + return !(y == x); + } +#endif + + template::value, int> = 0> + friend constexpr bool operator<(reference_wrapper x, reference_wrapper y) { + return x.get() < y.get(); + } + template::value, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, reference_wrapper y) { + return !(y < x); + } + template::value, int> = 0> + friend constexpr bool operator>(reference_wrapper x, reference_wrapper y) { + return y < x; + } + template::value, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, reference_wrapper y) { + return !(x < y); + } + + template::value, int> = 0> + friend constexpr bool operator<(reference_wrapper x, const T& y) { + return x.get() < y; + } + template::value, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, const T& y) { + return !(y < x); + } + template::value, int> = 0> + friend constexpr bool operator>(reference_wrapper x, const T& y) { + return y < x; + } + template::value, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, const T& y) { + return !(x < y); + } + template::value, int> = 0> + friend constexpr bool operator<(const T& x, reference_wrapper y) { + return x < y.get(); + } + template::value, int> = 0> + friend constexpr bool operator<=(const T& x, reference_wrapper y) { + return !(y < x); + } + template::value, int> = 0> + friend constexpr bool operator>(const T& x, reference_wrapper y) { + return y < x; + } + template::value, int> = 0> + friend constexpr bool operator>=(const T& x, reference_wrapper y) { + return !(x < y); + } + + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator<(reference_wrapper x, reference_wrapper y) { + return x.get() < y.get(); + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, reference_wrapper y) { + return !(y < x); + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator>(reference_wrapper x, reference_wrapper y) { + return y < x; + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, reference_wrapper y) { + return !(x < y); + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator<(reference_wrapper x, reference_wrapper> y) { + return x.get() < y.get(); + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, reference_wrapper> y) { + return !(y < x); + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator>(reference_wrapper x, reference_wrapper> y) { + return y < x; + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, reference_wrapper> y) { + return !(x < y); + } + + private: + constexpr reference_wrapper(in_place_t, T& ref) + : ptr_(preview::addressof(ref)) {} + + T* ptr_; +}; + +#if PREVIEW_CXX_VERSION >= 17 + +template< typename T > +reference_wrapper( T& ) -> reference_wrapper; + +#endif + +template +constexpr reference_wrapper ref(T& t) noexcept { + return reference_wrapper(t); +} + +template +constexpr reference_wrapper ref(reference_wrapper t) noexcept { + return t; +} + +template +constexpr reference_wrapper ref(std::reference_wrapper t) noexcept { + return reference_wrapper(t.get()); +} + + +template +constexpr reference_wrapper cref(const T& t) noexcept { + return reference_wrapper(t); +} + +template +constexpr reference_wrapper cref(reference_wrapper t) noexcept { + return t; +} + +template +constexpr reference_wrapper cref(std::reference_wrapper t) noexcept { + return reference_wrapper(t.get()); +} + +// TODO: Specialize std::basic_common_reference for preview::reference_wrapper + +template +struct is_reference_wrapper> : std::true_type {}; + +namespace detail { + +#if PREVIEW_CONFORM_CXX20_STANDARD + +template +concept ref_wrap_common_reference_exists_with = + is_specialization_v && + requires { typename preview::common_reference_t; } && + std::convertible_to>; + +#endif + +namespace preview_refwrap_to_std_refwrap { + +template +std::reference_wrapper ref(preview::reference_wrapper x) { + return std::reference_wrapper(x.get()); +} + +template +constexpr std::reference_wrapper cref(preview::reference_wrapper t) noexcept { + return std::reference_wrapper(t.get()); +} + +} // namespace preview_refwrap_to_std_refwrap +} // namespace detail +} // namespace preview + +namespace std { + +using preview::detail::preview_refwrap_to_std_refwrap::ref; +using preview::detail::preview_refwrap_to_std_refwrap::cref; + +} // namespace std + +#if PREVIEW_CONFORM_CXX20_STANDARD + +template class RQual, template class TQual> +requires (preview::detail::ref_wrap_common_reference_exists_with, TQual> && + !preview::detail::ref_wrap_common_reference_exists_with, RQual>) +struct std::basic_common_reference { + using type = std::common_reference_t>; +}; + +template class TQual, template class RQual> +requires (preview::detail::ref_wrap_common_reference_exists_with, TQual> && + !preview::detail::ref_wrap_common_reference_exists_with, RQual>) +struct std::basic_common_reference { + using type = std::common_reference_t>; +}; + +#endif + +#endif // PREVIEW_FUNCTIONAL_REFERENCE_WRAPPER_H_ diff --git a/include/preview/__ranges/ref_view.h b/include/preview/__ranges/ref_view.h index 545c617b..ddd33566 100644 --- a/include/preview/__ranges/ref_view.h +++ b/include/preview/__ranges/ref_view.h @@ -10,6 +10,7 @@ #include "preview/__concepts/convertible_to.h" #include "preview/__concepts/different_from.h" +#include "preview/__functional/reference_wrapper.h" #include "preview/__memory/addressof.h" #include "preview/__ranges/contiguous_range.h" #include "preview/__ranges/enable_borrowed_range.h" @@ -26,19 +27,6 @@ namespace preview { namespace ranges { -namespace detail { -namespace ref_view_fn { - -template static void fun(R&); -template static void fun(R&&) = delete; - -template -struct fallback_to_lref : std::false_type {}; -template -struct fallback_to_lref(std::declval()))>> : std::true_type {}; - -} // namespace ref_view_fn -} // namespace detail template class ref_view : public view_interface> { @@ -49,7 +37,7 @@ class ref_view : public view_interface> { template, convertible_to, - detail::ref_view_fn::fallback_to_lref + preview::detail::can_bind_to_reference >::value, int> = 0> PREVIEW_CONSTEXPR_AFTER_CXX17 ref_view(T&& t) noexcept : r_(preview::addressof(static_cast(std::forward(t)))) {} diff --git a/include/preview/__type_traits/unwrap_reference.h b/include/preview/__type_traits/unwrap_reference.h index 9c3e8db6..2289d612 100644 --- a/include/preview/__type_traits/unwrap_reference.h +++ b/include/preview/__type_traits/unwrap_reference.h @@ -8,6 +8,8 @@ #include #include +#include "preview/__functional/reference_wrapper.h" + namespace preview { template @@ -20,6 +22,11 @@ struct unwrap_reference> { using type = T&; }; +template +struct unwrap_reference> { + using type = T&; +}; + template using unwrap_reference_t = typename unwrap_reference::type; diff --git a/include/preview/functional.h b/include/preview/functional.h index 6c83162c..c0c3beb6 100644 --- a/include/preview/functional.h +++ b/include/preview/functional.h @@ -19,6 +19,7 @@ # include "preview/__functional/less_equal.h" # include "preview/__functional/not_equal_to.h" # include "preview/__functional/not_fn.h" +# include "preview/__functional/reference_wrapper.h" # include "preview/__functional/wrap_functor.h" # include "preview/__type_traits/unwrap_reference.h" From def6fde43a13e19ed9dcd392cdb8613169f48dd7 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 02:15:33 +0900 Subject: [PATCH 8/9] Add test --- .../preview/__functional/reference_wrapper.h | 220 ++++++++++++++++-- test/functional.cc | 120 ++++++++++ 2 files changed, 321 insertions(+), 19 deletions(-) diff --git a/include/preview/__functional/reference_wrapper.h b/include/preview/__functional/reference_wrapper.h index e2196eef..27bfc66b 100644 --- a/include/preview/__functional/reference_wrapper.h +++ b/include/preview/__functional/reference_wrapper.h @@ -59,10 +59,32 @@ struct can_bind_to_reference_noexcept : bool_constant -class reference_wrapper { +class reference_wrapper +#if PREVIEW_CONFORM_CXX20_STANDARD + : public std::reference_wrapper +#endif +{ + +#if PREVIEW_CONFORM_CXX20_STANDARD + using base = std::reference_wrapper; +#else + constexpr reference_wrapper(in_place_t, T& ref) + : ptr_(preview::addressof(ref)) {} + + T* ptr_; +#endif + public: using type = T; +#if PREVIEW_CONFORM_CXX20_STANDARD + using base::base; + using base::operator=; + using base::get; + using base::operator type &; + using base::operator(); +#else + template, negation< std::is_same, preview::reference_wrapper> >, @@ -90,21 +112,22 @@ class reference_wrapper { return *ptr_; } - // Not a standard function! This is required for std::invoke to handle reference_wrapper correctly. - constexpr T& operator*() const noexcept { - return *ptr_; + template + constexpr invoke_result_t + operator()(ArgTypes&&... args) const noexcept(is_nothrow_invocable::value) { + static_assert(is_complete_v, "T must be complete type"); + return preview::detail::INVOKE(get(), std::forward(args)...); } +#endif // Not a standard function! Use this function on deduced context is needed std::reference_wrapper to_std() { return get(); } - template - constexpr invoke_result_t - operator()(ArgTypes&&... args) const noexcept(is_nothrow_invocable::value) { - static_assert(is_complete_v, "T must be complete type"); - return preview::detail::INVOKE(get(), std::forward(args)...); + // Not a standard function! This is required for std::invoke to handle reference_wrapper correctly. + constexpr T& operator*() const noexcept { + return get(); } template::value, int> = 0> @@ -142,17 +165,17 @@ class reference_wrapper { friend constexpr bool operator==(reference_wrapper x, reference_wrapper y) { return x.get() == y.get(); } + // const T == T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator==(reference_wrapper x, reference_wrapper> y) { + return y.get() == x.get(); + } #if !PREVIEW_CONFORM_CXX20_STANDARD // T != const T template>, rel_ops::is_equality_comparable>, int> = 0> friend constexpr bool operator!=(reference_wrapper x, reference_wrapper y) { return !(x == y); } - // const T == T - template, rel_ops::is_equality_comparable&, U&>>, int> = 0> - friend constexpr bool operator==(reference_wrapper x, reference_wrapper> y) { - return y.get() == x.get(); - } // const T != T template, rel_ops::is_equality_comparable&, U&>>, int> = 0> friend constexpr bool operator!=(reference_wrapper x, reference_wrapper> y) { @@ -243,11 +266,171 @@ class reference_wrapper { return !(x < y); } - private: - constexpr reference_wrapper(in_place_t, T& ref) - : ptr_(preview::addressof(ref)) {} - T* ptr_; + // Comparison with std::reference_wrapper + template::value, int> = 0> + friend constexpr bool operator==(reference_wrapper x, std::reference_wrapper y) { + return x.get() == y.get(); + } +#if !PREVIEW_CONFORM_CXX20_STANDARD + template::value, int> = 0> + friend constexpr bool operator==(std::reference_wrapper x, reference_wrapper y) { + return x.get() == y.get(); + } + template::value, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, std::reference_wrapper y) { + return !(x == y); + } + template::value, int> = 0> + friend constexpr bool operator!=(std::reference_wrapper x, reference_wrapper y) { + return !(x == y); + } +#endif + + // Comparison with std::reference_wrapper + template>, rel_ops::is_equality_comparable>, int> = 0> + friend constexpr bool operator==(reference_wrapper x, std::reference_wrapper y) { + return x.get() == y.get(); + } + // const T == T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator==(reference_wrapper x, std::reference_wrapper> y) { + return y.get() == x.get(); + } +#if !PREVIEW_CONFORM_CXX20_STANDARD + // T != const T + template>, rel_ops::is_equality_comparable>, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, std::reference_wrapper y) { + return !(x == y); + } + // const T != T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator!=(reference_wrapper x, std::reference_wrapper> y) { + return !(y == x); + } +#endif + + template>, rel_ops::is_equality_comparable>, int> = 0> + friend constexpr bool operator==(std::reference_wrapper x, reference_wrapper y) { + return y.get() == x; + } + // const T == T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator==(std::reference_wrapper> x, reference_wrapper y) { + return x.get() == y.get(); + } +#if !PREVIEW_CONFORM_CXX20_STANDARD + // T != const T + template>, rel_ops::is_equality_comparable>, int> = 0> + friend constexpr bool operator!=(std::reference_wrapper x, reference_wrapper y) { + return !(y == x); + } + // const T != T + template, rel_ops::is_equality_comparable&, U&>>, int> = 0> + friend constexpr bool operator!=(std::reference_wrapper> x, reference_wrapper y) { + return !(y == x); + } +#endif + + + template::value, int> = 0> + friend constexpr bool operator<(reference_wrapper x, std::reference_wrapper y) { + return x.get() < y.get(); + } + template::value, int> = 0> + friend constexpr bool operator<(std::reference_wrapper x, reference_wrapper y) { + return x.get() < y.get(); + } + template::value, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, std::reference_wrapper y) { + return !(y < x); + } + template::value, int> = 0> + friend constexpr bool operator<=(std::reference_wrapper x, reference_wrapper y) { + return !(y < x); + } + template::value, int> = 0> + friend constexpr bool operator>(reference_wrapper x, std::reference_wrapper y) { + return y < x; + } + template::value, int> = 0> + friend constexpr bool operator>(std::reference_wrapper x, reference_wrapper y) { + return y < x; + } + template::value, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, std::reference_wrapper y) { + return !(x < y); + } + template::value, int> = 0> + friend constexpr bool operator>=(std::reference_wrapper x, reference_wrapper y) { + return !(x < y); + } + + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator<(reference_wrapper x, std::reference_wrapper y) { + return x.get() < y.get(); + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, std::reference_wrapper y) { + return !(y < x); + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator>(reference_wrapper x, std::reference_wrapper y) { + return y < x; + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, std::reference_wrapper y) { + return !(x < y); + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator<(reference_wrapper x, std::reference_wrapper> y) { + return x.get() < y.get(); + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator<=(reference_wrapper x, std::reference_wrapper> y) { + return !(y < x); + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator>(reference_wrapper x, std::reference_wrapper> y) { + return y < x; + } + template, detail::synth_three_way_possible&>>, int> = 0> + friend constexpr bool operator>=(reference_wrapper x, std::reference_wrapper> y) { + return !(x < y); + } + + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator<(std::reference_wrapper x, reference_wrapper y) { + return x.get() < y.get(); + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator<=(std::reference_wrapper x, reference_wrapper y) { + return !(y < x); + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator>(std::reference_wrapper x, reference_wrapper y) { + return y < x; + } + template>, detail::synth_three_way_possible>, int> = 0> + friend constexpr bool operator>=(std::reference_wrapper x, reference_wrapper y) { + return !(x < y); + } + template, detail::synth_three_way_possible&, U&>>, int> = 0> + friend constexpr bool operator<(std::reference_wrapper> x, reference_wrapper y) { + return x.get() < y.get(); + } + template, detail::synth_three_way_possible&, U&>>, int> = 0> + friend constexpr bool operator<=(std::reference_wrapper> x, reference_wrapper y) { + return !(y < x); + } + template, detail::synth_three_way_possible&, U&>>, int> = 0> + friend constexpr bool operator>(std::reference_wrapper> x, reference_wrapper y) { + return y < x; + } + template, detail::synth_three_way_possible&, U&>>, int> = 0> + friend constexpr bool operator>=(std::reference_wrapper> x, reference_wrapper y) { + return !(x < y); + } }; #if PREVIEW_CXX_VERSION >= 17 @@ -272,7 +455,6 @@ constexpr reference_wrapper ref(std::reference_wrapper t) noexcept { return reference_wrapper(t.get()); } - template constexpr reference_wrapper cref(const T& t) noexcept { return reference_wrapper(t); diff --git a/test/functional.cc b/test/functional.cc index 181821f9..73d6032b 100644 --- a/test/functional.cc +++ b/test/functional.cc @@ -1,5 +1,9 @@ #include "preview/core.h" #include "preview/functional.h" + +#include +#include + #include "preview/string_view.h" #include "gtest.h" @@ -137,3 +141,119 @@ TEST(VERSIONED(Functional), not_fn) { static_assert(differ_cpp26(2, 2) == false); #endif } + +template +void foo(std::reference_wrapper x) {} + +struct A { + explicit A(int data) : data(data) {} + + int data{}; + int mem_fn() { return data; } + + friend constexpr bool operator==(const A& x, const A& y) { + return x.data == y.data; + } + friend constexpr bool operator<(const A& x, const A& y) { + return x.data < y.data; + } +}; + +TEST(VERSIONED(Functional), reference_wrapper) { + A x{10}; + auto r = preview::ref(x); + EXPECT_EQ(r, /* == */ A{10}); EXPECT_EQ(A{10}, /* == */ r); + EXPECT_NE(r, /* != */ A{0 }); EXPECT_NE(A{0 }, /* != */ r); + EXPECT_GT(r, /* > */ A{9 }); EXPECT_GT(A{11}, /* > */ r); + EXPECT_GE(r, /* >= */ A{9 }); EXPECT_GE(A{11}, /* >= */ r); + EXPECT_LT(r, /* < */ A{11}); EXPECT_LT(A{9 }, /* < */ r); + EXPECT_LE(r, /* <= */ A{11}); EXPECT_LE(A{9 }, /* <= */ r); + + EXPECT_EQ(r, r); + EXPECT_EQ(r, preview::cref(x)); EXPECT_EQ(preview::cref(x), r); + + A y{20}; + EXPECT_NE(r, preview::ref(y)); EXPECT_NE(r, preview::cref(y)); + EXPECT_GT(preview::ref(y), r); EXPECT_GT(preview::cref(y), r); + EXPECT_GE(preview::ref(y), r); EXPECT_GE(preview::cref(y), r); + EXPECT_LT(r, preview::ref(y)); EXPECT_LT(r, preview::cref(y)); + EXPECT_LE(r, preview::ref(y)); EXPECT_LE(r, preview::cref(y)); + + EXPECT_EQ(preview::invoke(&A::data, r), 10); + preview::invoke(&A::data, r) += 5; + EXPECT_EQ(preview::invoke(&A::data, r), 15); + EXPECT_EQ(preview::invoke(&A::mem_fn, r), 15); + + { + auto cr = preview::cref(x); + A z{30}; + + EXPECT_EQ(r, std::ref(x)); EXPECT_EQ(std::ref(x) , r ); + EXPECT_EQ(r, std::cref(x)); EXPECT_EQ(std::cref(x), r ); + + (void)(cr != std::ref(x)); + (void)(std::ref(x) == cr); + + EXPECT_EQ(cr, std::ref(x)); EXPECT_EQ(std::ref(x) , cr); + EXPECT_EQ(cr, std::cref(x)); EXPECT_EQ(std::cref(x), cr); + + EXPECT_NE(r, std::ref(y)); EXPECT_NE(std::ref(y) , r ); + EXPECT_NE(r, std::cref(y)); EXPECT_NE(std::cref(y), r ); + EXPECT_NE(cr, std::ref(y)); EXPECT_NE(std::ref(y) , cr); + EXPECT_NE(cr, std::cref(y)); EXPECT_NE(std::cref(y), cr); + + // x < y < z + + EXPECT_GT(preview::ref(z), std::ref(y)); EXPECT_GT(std::ref(y), preview::ref(x)); + EXPECT_GT(preview::ref(z), std::cref(y)); EXPECT_GT(std::cref(y), preview::ref(x)); + EXPECT_GT(preview::cref(z), std::ref(y)); EXPECT_GT(std::ref(y), preview::cref(x)); + EXPECT_GT(preview::cref(z), std::cref(y)); EXPECT_GT(std::cref(y), preview::cref(x)); + + EXPECT_GE(preview::ref(z), std::ref(y)); EXPECT_GE(std::ref(y), preview::ref(x)); + EXPECT_GE(preview::ref(z), std::cref(y)); EXPECT_GE(std::cref(y), preview::ref(x)); + EXPECT_GE(preview::cref(z), std::ref(y)); EXPECT_GE(std::ref(y), preview::cref(x)); + EXPECT_GE(preview::cref(z), std::cref(y)); EXPECT_GE(std::cref(y), preview::cref(x)); + + EXPECT_LT(preview::ref(x), std::ref(y)); EXPECT_LT(std::ref(y), preview::ref(z)); + EXPECT_LT(preview::ref(x), std::cref(y)); EXPECT_LT(std::cref(y), preview::ref(z)); + EXPECT_LT(preview::cref(x), std::ref(y)); EXPECT_LT(std::ref(y), preview::cref(z)); + EXPECT_LT(preview::cref(x), std::cref(y)); EXPECT_LT(std::cref(y), preview::cref(z)); + + EXPECT_LE(preview::ref(x), std::ref(y)); EXPECT_LE(std::ref(y), preview::ref(z)); + EXPECT_LE(preview::ref(x), std::cref(y)); EXPECT_LE(std::cref(y), preview::ref(z)); + EXPECT_LE(preview::cref(x), std::ref(y)); EXPECT_LE(std::ref(y), preview::cref(z)); + EXPECT_LE(preview::cref(x), std::cref(y)); EXPECT_LE(std::cref(y), preview::cref(z)); + } + +#if PREVIEW_CXX_VERSION >= 17 + std::invoke(&A::data, r) -= 5; + EXPECT_EQ(std::invoke(&A::data, r), 10); + EXPECT_EQ(std::invoke(&A::mem_fn, r), 10); +#endif + +#if PREVIEW_CONFORM_CXX20_STANDARD + (void)foo(r); +#endif + +// preview::simple_common_reference_t&> + + using T = int&; + using R = preview::reference_wrapper&; + + using bcr = preview::basic_common_reference< + int, + preview::reference_wrapper, + preview::detail::basic_common_reference_qual_gen::qual, + preview::detail::basic_common_reference_qual_gen::qual>; + using t = typename bcr::type; +// +// static_assert(preview::detail::common_reference_tag_2::value); +// +// + static_assert(std::is_same, int&>::value, ""); + static_assert(std::is_same&>, int&>::value, ""); + static_assert(std::is_same&>, int&>::value, ""); + static_assert(std::is_same&>, int&>::value, ""); +// static_assert(std::is_same_v< std::common_reference_t&>, int&>); + +} From 6c8e9b8184d5e2ebf272a197df1c55c2f8fb9748 Mon Sep 17 00:00:00 2001 From: Yong Gyu Lee Date: Fri, 18 Oct 2024 02:25:11 +0900 Subject: [PATCH 9/9] Fix gcc 11 --- .../preview/__functional/reference_wrapper.h | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/preview/__functional/reference_wrapper.h b/include/preview/__functional/reference_wrapper.h index 27bfc66b..f1e4b1be 100644 --- a/include/preview/__functional/reference_wrapper.h +++ b/include/preview/__functional/reference_wrapper.h @@ -512,18 +512,18 @@ using preview::detail::preview_refwrap_to_std_refwrap::cref; #if PREVIEW_CONFORM_CXX20_STANDARD -template class RQual, template class TQual> -requires (preview::detail::ref_wrap_common_reference_exists_with, TQual> && - !preview::detail::ref_wrap_common_reference_exists_with, RQual>) -struct std::basic_common_reference { - using type = std::common_reference_t>; -}; - -template class TQual, template class RQual> -requires (preview::detail::ref_wrap_common_reference_exists_with, TQual> && - !preview::detail::ref_wrap_common_reference_exists_with, RQual>) -struct std::basic_common_reference { - using type = std::common_reference_t>; +// Single defition to prevent some old compilers complaining duplicated difinition + +template class TQual, template class UQual> +requires ( + (preview::detail::ref_wrap_common_reference_exists_with, UQual> && + !preview::detail::ref_wrap_common_reference_exists_with, TQual>) || + (preview::detail::ref_wrap_common_reference_exists_with, TQual> && + !preview::detail::ref_wrap_common_reference_exists_with, UQual>) +) +struct std::basic_common_reference { + using type = typename preview::detail::bcr_specialization::basic_common_reference_base< + T, U, TQual, UQual, preview::detail::bcr_specialization::kReferenceWrapper>::type; }; #endif