Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LWG-3862: basic_const_iterator's common_type specialization is underconstrained #3471

Merged
merged 1 commit into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -2062,16 +2062,19 @@ public:
};

template <class _Ty1, common_with<_Ty1> _Ty2>
requires input_iterator<common_type_t<_Ty1, _Ty2>>
struct common_type<basic_const_iterator<_Ty1>, _Ty2> {
using type = basic_const_iterator<common_type_t<_Ty1, _Ty2>>;
};

template <class _Ty1, common_with<_Ty1> _Ty2>
requires input_iterator<common_type_t<_Ty1, _Ty2>>
struct common_type<_Ty2, basic_const_iterator<_Ty1>> {
using type = basic_const_iterator<common_type_t<_Ty1, _Ty2>>;
};

template <class _Ty1, common_with<_Ty1> _Ty2>
requires input_iterator<common_type_t<_Ty1, _Ty2>>
struct common_type<basic_const_iterator<_Ty1>, basic_const_iterator<_Ty2>> {
using type = basic_const_iterator<common_type_t<_Ty1, _Ty2>>;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,76 @@ static_assert(!CanIterConstRef<int>);
static_assert(!CanIterConstRef<list<int>>);
static_assert(!CanIterConstRef<deque<int>>);

namespace test_common_type {
struct CommonThing {};

template <class T>
struct InIter {
using value_type = T;
using difference_type = ptrdiff_t;

value_type& operator*() const; // not defined
InIter& operator++(); // not defined
void operator++(int); // not defined
operator CommonThing() const; // not defined
};

static_assert(input_iterator<InIter<int>>);
static_assert(input_iterator<InIter<long>>);
} // namespace test_common_type

template <class T, class U>
struct std::common_type<test_common_type::InIter<T>, test_common_type::InIter<U>> {
using type = test_common_type::CommonThing;
};

static_assert(common_with<test_common_type::InIter<int>, test_common_type::InIter<long>>);

namespace test_common_type {
template <class T, class U>
concept CanCommonType = requires { typename common_type_t<T, U>; };

// Validate invalid common types
static_assert(!CanCommonType<basic_const_iterator<int*>, long*>);
static_assert(!CanCommonType<int*, basic_const_iterator<long*>>);
static_assert(!CanCommonType<basic_const_iterator<int*>, basic_const_iterator<long*>>);
static_assert(!CanCommonType<basic_const_iterator<InIter<int>>, InIter<long>>);
static_assert(!CanCommonType<InIter<int>, basic_const_iterator<InIter<long>>>);
static_assert(!CanCommonType<basic_const_iterator<InIter<int>>, basic_const_iterator<InIter<long>>>);

// Validate common_type
static_assert(same_as<common_type_t<basic_const_iterator<int*>, const int*>, basic_const_iterator<const int*>>);
static_assert(same_as<common_type_t<const int*, basic_const_iterator<int*>>, basic_const_iterator<const int*>>);
static_assert(same_as<common_type_t<basic_const_iterator<const int*>, int*>, basic_const_iterator<const int*>>);
static_assert(same_as<common_type_t<int*, basic_const_iterator<const int*>>, basic_const_iterator<const int*>>);
static_assert(same_as<common_type_t<basic_const_iterator<int*>, basic_const_iterator<const int*>>,
basic_const_iterator<const int*>>);
static_assert(same_as<common_type_t<basic_const_iterator<const int*>, basic_const_iterator<int*>>,
basic_const_iterator<const int*>>);

static_assert(same_as<common_type_t<basic_const_iterator<volatile int*>, const int*>,
basic_const_iterator<const volatile int*>>);
static_assert(same_as<common_type_t<const int*, basic_const_iterator<volatile int*>>,
basic_const_iterator<const volatile int*>>);
static_assert(same_as<common_type_t<volatile int*, basic_const_iterator<const int*>>,
basic_const_iterator<const volatile int*>>);
static_assert(same_as<common_type_t<basic_const_iterator<const int*>, volatile int*>,
basic_const_iterator<const volatile int*>>);

template <class T, class U>
requires requires {
typename common_type_t<T, basic_const_iterator<U>>;
typename common_type_t<basic_const_iterator<T>, U>;
typename common_type_t<basic_const_iterator<T>, basic_const_iterator<U>>;
}
void test_lwg3862(); // not defined

template <class T, class U>
concept VerifyLWG3862 = requires { test_lwg3862<T, U>(); };

static_assert(!VerifyLWG3862<InIter<int>, InIter<long>>); // Hard error before LWG-3862
} // namespace test_common_type

namespace test_pointer {
using Ptr = int*;
static_assert(CanIterConstRef<Ptr>);
Expand All @@ -50,12 +120,6 @@ namespace test_pointer {
static_assert(same_as<const_iterator<ConstPtr>, ConstPtr>);
static_assert(same_as<iter_reference_t<const_iterator<ConstPtr>>, const int&>);
static_assert(same_as<const_sentinel<ConstPtr>, ConstPtr>);

// Validate common_type
static_assert(same_as<common_type_t<basic_const_iterator<Ptr>, ConstPtr>, basic_const_iterator<ConstPtr>>);
static_assert(same_as<common_type_t<ConstPtr, basic_const_iterator<Ptr>>, basic_const_iterator<ConstPtr>>);
static_assert(same_as<common_type_t<basic_const_iterator<Ptr>, basic_const_iterator<ConstPtr>>,
basic_const_iterator<ConstPtr>>);
} // namespace test_pointer

namespace test_random_access_iter {
Expand Down