libstdc++: Fix std::indirectly_readable ambiguity [LWG 3446]
This implements the proposed resolution of LWG 3446. I'm also adding another new constrained specialization which isn't proposed by 3446, to resolve the ambiguity when a type has both value_type and element_type but denoting different types. libstdc++-v3/ChangeLog: * include/bits/iterator_concepts.h (indirectly_readable): Add partial specializations to resolve ambiguities (LWG 3446). * testsuite/24_iterators/associated_types/readable.traits.cc: Check types with both value_type and element_type.
This commit is contained in:
parent
a0e6f05d26
commit
186aa63045
@ -220,6 +220,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
template<typename _Tp> requires is_object_v<_Tp>
|
||||
struct __cond_value_type<_Tp>
|
||||
{ using value_type = remove_cv_t<_Tp>; };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __has_member_value_type
|
||||
= requires { typename _Tp::value_type; };
|
||||
|
||||
template<typename _Tp>
|
||||
concept __has_member_element_type
|
||||
= requires { typename _Tp::element_type; };
|
||||
|
||||
} // namespace __detail
|
||||
|
||||
template<typename> struct indirectly_readable_traits { };
|
||||
@ -238,16 +247,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
: indirectly_readable_traits<_Iter>
|
||||
{ };
|
||||
|
||||
template<typename _Tp> requires requires { typename _Tp::value_type; }
|
||||
template<__detail::__has_member_value_type _Tp>
|
||||
struct indirectly_readable_traits<_Tp>
|
||||
: __detail::__cond_value_type<typename _Tp::value_type>
|
||||
{ };
|
||||
|
||||
template<typename _Tp> requires requires { typename _Tp::element_type; }
|
||||
template<__detail::__has_member_element_type _Tp>
|
||||
struct indirectly_readable_traits<_Tp>
|
||||
: __detail::__cond_value_type<typename _Tp::element_type>
|
||||
{ };
|
||||
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 3446. indirectly_readable_traits ambiguity for types with both [...]
|
||||
template<__detail::__has_member_value_type _Tp>
|
||||
requires __detail::__has_member_element_type<_Tp>
|
||||
&& same_as<remove_cv_t<typename _Tp::element_type>,
|
||||
remove_cv_t<typename _Tp::value_type>>
|
||||
struct indirectly_readable_traits<_Tp>
|
||||
: __detail::__cond_value_type<typename _Tp::value_type>
|
||||
{ };
|
||||
|
||||
// LWG 3446 doesn't add this, but it's needed for the case where
|
||||
// value_type and element_type are both present, but not the same type.
|
||||
template<__detail::__has_member_value_type _Tp>
|
||||
requires __detail::__has_member_element_type<_Tp>
|
||||
struct indirectly_readable_traits<_Tp>
|
||||
{ };
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
template<typename _Tp>
|
||||
|
@ -141,3 +141,29 @@ struct J
|
||||
// iterator_traits<J> matches constrained specialization in the library,
|
||||
// so use its value_type.
|
||||
static_assert( check_alias<J, int> );
|
||||
|
||||
struct I2
|
||||
{
|
||||
using element_type = int;
|
||||
};
|
||||
// iterator_traits<I2> is not specialized, and no standard specialization
|
||||
// matches, so use indirectly_readable_traits.
|
||||
static_assert( check_alias<I2, std::indirectly_readable_traits<I2>::value_type> );
|
||||
|
||||
// LWG 3446
|
||||
struct I3
|
||||
{
|
||||
using value_type = long;
|
||||
using element_type = const long;
|
||||
};
|
||||
// iterator_traits<I3> is not specialized, and no standard specialization
|
||||
// matches, so use indirectly_readable_traits.
|
||||
static_assert( check_alias<I3, std::indirectly_readable_traits<I3>::value_type> );
|
||||
|
||||
// Correction to LWG 3446
|
||||
struct I4
|
||||
{
|
||||
using value_type = int;
|
||||
using element_type = long;
|
||||
};
|
||||
static_assert( ! has_alias<I4> );
|
||||
|
Loading…
Reference in New Issue
Block a user