[libc++] implement "pair" section of P2321R2 `zip`

Differential Revision: https://reviews.llvm.org/D131495
This commit is contained in:
Hui Xie 2022-08-09 14:56:30 +01:00
parent 926ccfef03
commit 83ead2bbc5
27 changed files with 962 additions and 174 deletions

View File

@ -1,27 +1,27 @@
Section,Description,Dependencies,Assignee,Complete
| `[tuple.syn] <https://wg21.link/tuple.syn>`_, "`[tuple] basic_common_reference, common_type <https://reviews.llvm.org/D116538>`_", None, Nikolas Klauser, |Complete|
| `[tuple.tuple] <https://wg21.link/tuple.tuple>`_, "`[tuple] constructor, assignment and swap overloads <https://reviews.llvm.org/D116621>`_", None, Nikolas Klauser, |In Progress|
| `[tuple.tuple] <https://wg21.link/tuple.tuple>`_, "`[tuple] constructor, assignment and swap overloads <https://reviews.llvm.org/D116621>`_", None, Hui Xie, |Complete|
| `[utility.syn] <https://wg21.link/utility.syn>`_, "[pair] basic_common_reference, common_type", None, Nikolas Klauser, |Complete|
| `[pairs.pair] <https://wg21.link/pairs.pair>`_, "[pair] constructor, assignment and swap overloads", None, Nikolas Klauser, |Not Started|
| `[pairs.pair] <https://wg21.link/pairs.pair>`_, "`[pair] constructor, assignment and swap overloads <https://reviews.llvm.org/D131495>`_", None, Hui Xie, |Complete|
"| `[memory.syn] <https://wg21.link/memory.syn>`_
| `[allocator.uses.construction] <https://wg21.link/allocator.uses.construction>`_", "[pair] uses_allocator_construction_args overloads", None, Unassigned, |Not Started|
| `[vector.bool] <https://wg21.link/vector.bool>`_, "[vector<bool>::reference] add const operator= overload", None, Nikolas Klauser, |Not Started|
| `[iterator.concept.winc] <https://wg21.link/iterator.concept.winc>`_, "Update weakly_comparable", None, Unassigned, |Not Started|
| `[vector.bool] <https://wg21.link/vector.bool>`_, "[vector<bool>::reference] add const operator= overload", None, Hui Xie, |Not Started|
| `[iterator.concept.winc] <https://wg21.link/iterator.concept.winc>`_, "Update weakly_comparable", None, Hui Xie, |Not Started|
| `[range.zip] <https://wg21.link/ranges.syn>`_, "`zip_view <https://reviews.llvm.org/D122806>`_", "| `zip_view::iterator`
| `zip_view::sentinel`", Hui Xie, |Complete|
| `[range.zip.iterator] <https://wg21.link/range.zip.iterator>`_, "`zip_view::iterator <https://reviews.llvm.org/D122806>`_", None, Hui Xie, |Complete|
| `[range.zip.sentinel] <https://wg21.link/range.zip.sentinel>`_, "`zip_view::sentinel <https://reviews.llvm.org/D122806>`_", None, Hui Xie, |Complete|
| `[range.zip.transform.view] <https://wg21.link/range.zip.transform.view>`_, "zip_transform_view", "| `zip_transform_view::iterator`
| `zip_transform_view::sentinel`", Unassigned, |Not Started|
| `[range.zip.transform.iterator] <https://wg21.link/range.zip.transform.iterator>`_, "zip_transform_view::iterator", None, Unassigned, |Not Started|
| `[range.zip.transform.sentinel] <https://wg21.link/range.zip.transform.sentinel>`_, "zip_transform_view::sentinel", None, Unassigned, |Not Started|
| `zip_transform_view::sentinel`", Hui Xie, |Not Started|
| `[range.zip.transform.iterator] <https://wg21.link/range.zip.transform.iterator>`_, "zip_transform_view::iterator", None, Hui Xie, |Not Started|
| `[range.zip.transform.sentinel] <https://wg21.link/range.zip.transform.sentinel>`_, "zip_transform_view::sentinel", None, Hui Xie, |Not Started|
| `[range.adjacent.view] <https://wg21.link/range.adjacent.view>`_, "adjacent_view", "| `adjacent_view::iterator`
| `adjacent_view::sentinel`", Unassigned, |Not Started|
| `[range.adjacent.iterator] <https://wg21.link/range.adjacent.iterator>`_, "adjacent_view::iterator", None, Unassigned, |Not Started|
| `[range.adjacent.sentinel] <https://wg21.link/range.adjacent.sentinel>`_, "adjacent_view::sentinel", None, Unassigned, |Not Started|
| `adjacent_view::sentinel`", Hui Xie, |Not Started|
| `[range.adjacent.iterator] <https://wg21.link/range.adjacent.iterator>`_, "adjacent_view::iterator", None, unassigned, |Not Started|
| `[range.adjacent.sentinel] <https://wg21.link/range.adjacent.sentinel>`_, "adjacent_view::sentinel", None, unassigned, |Not Started|
| `[range.adjacent.transform.view] <https://wg21.link/range.adjacent.transform.view>`_, "adjacent_transform_view", "| `adjacent_transform_view::iterator`,
| `adjacent_transform_view::sentinel`", Unassigned, |Not Started|
| `[range.adjacent.transform.iterator] <https://wg21.link/range.adjacent.transform.iterator>`_, "adjacent_transform_view::iterator", None, Unassigned, |Not Started|
| `[range.adjacent.transform.sentinel] <https://wg21.link/range.adjacent.transform.sentinel>`_, "adjacent_transform_view::sentinel", None, Unassigned, |Not Started|
| `adjacent_transform_view::sentinel`", Hui Xie, |Not Started|
| `[range.adjacent.transform.iterator] <https://wg21.link/range.adjacent.transform.iterator>`_, "adjacent_transform_view::iterator", None, Hui Xie, |Not Started|
| `[range.adjacent.transform.sentinel] <https://wg21.link/range.adjacent.transform.sentinel>`_, "adjacent_transform_view::sentinel", None, Hui Xie, |Not Started|
| `[ranges.syn] <https://wg21.link/ranges.syn>`_, "enable_borrowed_range zip_view and adjacent_view", "| `zip_view`
| `adjacent_view`", Unassigned, |Not Started|
| `adjacent_view`", Hui Xie, |Not Started|

1 Section Description Dependencies Assignee Complete
2 | `[tuple.syn] <https://wg21.link/tuple.syn>`_ `[tuple] basic_common_reference, common_type <https://reviews.llvm.org/D116538>`_ None Nikolas Klauser |Complete|
3 | `[tuple.tuple] <https://wg21.link/tuple.tuple>`_ `[tuple] constructor, assignment and swap overloads <https://reviews.llvm.org/D116621>`_ None Nikolas Klauser Hui Xie |In Progress| |Complete|
4 | `[utility.syn] <https://wg21.link/utility.syn>`_ [pair] basic_common_reference, common_type None Nikolas Klauser |Complete|
5 | `[pairs.pair] <https://wg21.link/pairs.pair>`_ [pair] constructor, assignment and swap overloads `[pair] constructor, assignment and swap overloads <https://reviews.llvm.org/D131495>`_ None Nikolas Klauser Hui Xie |Not Started| |Complete|
6 | `[memory.syn] <https://wg21.link/memory.syn>`_ | `[allocator.uses.construction] <https://wg21.link/allocator.uses.construction>`_ [pair] uses_allocator_construction_args overloads None Unassigned |Not Started|
7 | `[vector.bool] <https://wg21.link/vector.bool>`_ [vector<bool>::reference] add const operator= overload None Nikolas Klauser Hui Xie |Not Started|
8 | `[iterator.concept.winc] <https://wg21.link/iterator.concept.winc>`_ Update weakly_comparable None Unassigned Hui Xie |Not Started|
9 | `[range.zip] <https://wg21.link/ranges.syn>`_ `zip_view <https://reviews.llvm.org/D122806>`_ | `zip_view::iterator` | `zip_view::sentinel` Hui Xie |Complete|
10 | `[range.zip.iterator] <https://wg21.link/range.zip.iterator>`_ `zip_view::iterator <https://reviews.llvm.org/D122806>`_ None Hui Xie |Complete|
11 | `[range.zip.sentinel] <https://wg21.link/range.zip.sentinel>`_ `zip_view::sentinel <https://reviews.llvm.org/D122806>`_ None Hui Xie |Complete|
12 | `[range.zip.transform.view] <https://wg21.link/range.zip.transform.view>`_ zip_transform_view | `zip_transform_view::iterator` | `zip_transform_view::sentinel` Unassigned Hui Xie |Not Started|
13 | `[range.zip.transform.iterator] <https://wg21.link/range.zip.transform.iterator>`_ zip_transform_view::iterator None Unassigned Hui Xie |Not Started|
14 | `[range.zip.transform.sentinel] <https://wg21.link/range.zip.transform.sentinel>`_ zip_transform_view::sentinel None Unassigned Hui Xie |Not Started|
15 | `[range.adjacent.view] <https://wg21.link/range.adjacent.view>`_ adjacent_view | `adjacent_view::iterator` | `adjacent_view::sentinel` Unassigned Hui Xie |Not Started|
16 | `[range.adjacent.iterator] <https://wg21.link/range.adjacent.iterator>`_ adjacent_view::iterator None Unassigned unassigned |Not Started|
17 | `[range.adjacent.sentinel] <https://wg21.link/range.adjacent.sentinel>`_ adjacent_view::sentinel None Unassigned unassigned |Not Started|
18 | `[range.adjacent.transform.view] <https://wg21.link/range.adjacent.transform.view>`_ adjacent_transform_view | `adjacent_transform_view::iterator`, | `adjacent_transform_view::sentinel` Unassigned Hui Xie |Not Started|
19 | `[range.adjacent.transform.iterator] <https://wg21.link/range.adjacent.transform.iterator>`_ adjacent_transform_view::iterator None Unassigned Hui Xie |Not Started|
20 | `[range.adjacent.transform.sentinel] <https://wg21.link/range.adjacent.transform.sentinel>`_ adjacent_transform_view::sentinel None Unassigned Hui Xie |Not Started|
21 | `[ranges.syn] <https://wg21.link/ranges.syn>`_ enable_borrowed_range zip_view and adjacent_view | `zip_view` | `adjacent_view` Unassigned Hui Xie |Not Started|
22
23
24
25
26
27

View File

@ -90,19 +90,25 @@ struct _LIBCPP_TEMPLATE_VIS pair
}
template <class _U1, class _U2>
static constexpr bool __enable_explicit() {
static constexpr bool __is_pair_constructible() {
return is_constructible<first_type, _U1>::value
&& is_constructible<second_type, _U2>::value
&& (!is_convertible<_U1, first_type>::value
|| !is_convertible<_U2, second_type>::value);
&& is_constructible<second_type, _U2>::value;
}
template <class _U1, class _U2>
static constexpr bool __is_implicit() {
return is_convertible<_U1, first_type>::value
&& is_convertible<_U2, second_type>::value;
}
template <class _U1, class _U2>
static constexpr bool __enable_explicit() {
return __is_pair_constructible<_U1, _U2>() && !__is_implicit<_U1, _U2>();
}
template <class _U1, class _U2>
static constexpr bool __enable_implicit() {
return is_constructible<first_type, _U1>::value
&& is_constructible<second_type, _U2>::value
&& is_convertible<_U1, first_type>::value
&& is_convertible<_U2, second_type>::value;
return __is_pair_constructible<_U1, _U2>() && __is_implicit<_U1, _U2>();
}
};
@ -198,6 +204,17 @@ struct _LIBCPP_TEMPLATE_VIS pair
is_nothrow_constructible<second_type, _U2>::value))
: first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {}
#if _LIBCPP_STD_VER > 20
template<class _U1, class _U2, __enable_if_t<
_CheckArgs::template __is_pair_constructible<_U1&, _U2&>()
>* = nullptr>
_LIBCPP_HIDE_FROM_ABI constexpr
explicit(!_CheckArgs::template __is_implicit<_U1&, _U2&>()) pair(pair<_U1, _U2>& __p)
noexcept((is_nothrow_constructible<first_type, _U1&>::value &&
is_nothrow_constructible<second_type, _U2&>::value))
: first(__p.first), second(__p.second) {}
#endif
template<class _U1, class _U2, typename enable_if<
_CheckArgs::template __enable_explicit<_U1 const&, _U2 const&>()
>::type* = nullptr>
@ -234,6 +251,18 @@ struct _LIBCPP_TEMPLATE_VIS pair
is_nothrow_constructible<second_type, _U2&&>::value))
: first(_VSTD::forward<_U1>(__p.first)), second(_VSTD::forward<_U2>(__p.second)) {}
#if _LIBCPP_STD_VER > 20
template<class _U1, class _U2, __enable_if_t<
_CheckArgs::template __is_pair_constructible<const _U1&&, const _U2&&>()
>* = nullptr>
_LIBCPP_HIDE_FROM_ABI constexpr
explicit(!_CheckArgs::template __is_implicit<const _U1&&, const _U2&&>())
pair(const pair<_U1, _U2>&& __p)
noexcept(is_nothrow_constructible<first_type, const _U1&&>::value &&
is_nothrow_constructible<second_type, const _U2&&>::value)
: first(std::move(__p.first)), second(std::move(__p.second)) {}
#endif
template<class _Tuple, typename enable_if<
_CheckTLC<_Tuple>::template __enable_explicit<_Tuple>()
>::type* = nullptr>
@ -286,6 +315,50 @@ struct _LIBCPP_TEMPLATE_VIS pair
return *this;
}
#if _LIBCPP_STD_VER > 20
_LIBCPP_HIDE_FROM_ABI constexpr
const pair& operator=(pair const& __p) const
noexcept(is_nothrow_copy_assignable_v<const first_type> &&
is_nothrow_copy_assignable_v<const second_type>)
requires(is_copy_assignable_v<const first_type> &&
is_copy_assignable_v<const second_type>) {
first = __p.first;
second = __p.second;
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr
const pair& operator=(pair&& __p) const
noexcept(is_nothrow_assignable_v<const first_type&, first_type> &&
is_nothrow_assignable_v<const second_type&, second_type>)
requires(is_assignable_v<const first_type&, first_type> &&
is_assignable_v<const second_type&, second_type>) {
first = std::forward<first_type>(__p.first);
second = std::forward<second_type>(__p.second);
return *this;
}
template<class _U1, class _U2>
_LIBCPP_HIDE_FROM_ABI constexpr
const pair& operator=(const pair<_U1, _U2>& __p) const
requires(is_assignable_v<const first_type&, const _U1&> &&
is_assignable_v<const second_type&, const _U2&>) {
first = __p.first;
second = __p.second;
return *this;
}
template<class _U1, class _U2>
_LIBCPP_HIDE_FROM_ABI constexpr
const pair& operator=(pair<_U1, _U2>&& __p) const
requires(is_assignable_v<const first_type&, _U1> &&
is_assignable_v<const second_type&, _U2>) {
first = std::forward<_U1>(__p.first);
second = std::forward<_U2>(__p.second);
return *this;
}
#endif // _LIBCPP_STD_VER > 20
template <class _Tuple, typename enable_if<
_CheckTLC<_Tuple>::template __enable_assign<_Tuple>()
>::type* = nullptr>
@ -306,6 +379,18 @@ struct _LIBCPP_TEMPLATE_VIS pair
swap(first, __p.first);
swap(second, __p.second);
}
#if _LIBCPP_STD_VER > 20
_LIBCPP_HIDE_FROM_ABI constexpr
void swap(const pair& __p) const
noexcept(__is_nothrow_swappable<const first_type>::value &&
__is_nothrow_swappable<const second_type>::value)
{
using std::swap;
swap(first, __p.first);
swap(second, __p.second);
}
#endif
private:
#ifndef _LIBCPP_CXX03_LANG
@ -422,6 +507,18 @@ swap(pair<_T1, _T2>& __x, pair<_T1, _T2>& __y)
__x.swap(__y);
}
#if _LIBCPP_STD_VER > 20
template <class _T1, class _T2>
requires (__is_swappable<const _T1>::value &&
__is_swappable<const _T2>::value)
_LIBCPP_HIDE_FROM_ABI constexpr
void swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
noexcept(noexcept(__x.swap(__y)))
{
__x.swap(__y);
}
#endif
template <class _T1, class _T2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX14
pair<typename __unwrap_ref_decay<_T1>::type, typename __unwrap_ref_decay<_T2>::type>

View File

@ -84,19 +84,29 @@ struct pair
explicit(see-below) constexpr pair();
explicit(see-below) pair(const T1& x, const T2& y); // constexpr in C++14
template <class U = T1, class V = T2> explicit(see-below) pair(U&&, V&&); // constexpr in C++14
template <class U, class V> constexpr explicit(see below) pair(pair<U, V>&); // since C++23
template <class U, class V> explicit(see-below) pair(const pair<U, V>& p); // constexpr in C++14
template <class U, class V> explicit(see-below) pair(pair<U, V>&& p); // constexpr in C++14
template <class U, class V>
constexpr explicit(see below) pair(const pair<U, V>&&); // since C++23
template <class... Args1, class... Args2>
pair(piecewise_construct_t, tuple<Args1...> first_args,
tuple<Args2...> second_args); // constexpr in C++20
constexpr const pair& operator=(const pair& p) const; // since C++23
template <class U, class V> pair& operator=(const pair<U, V>& p); // constexpr in C++20
template <class U, class V>
constexpr const pair& operator=(const pair<U, V>& p) const; // since C++23
pair& operator=(pair&& p) noexcept(is_nothrow_move_assignable<T1>::value &&
is_nothrow_move_assignable<T2>::value); // constexpr in C++20
constexpr const pair& operator=(pair&& p) const; // since C++23
template <class U, class V> pair& operator=(pair<U, V>&& p); // constexpr in C++20
template <class U, class V>
constexpr const pair& operator=(pair<U, V>&& p) const; // since C++23
void swap(pair& p) noexcept(is_nothrow_swappable_v<T1> &&
is_nothrow_swappable_v<T2>); // constexpr in C++20
constexpr void swap(const pair& p) const noexcept(see below); // since C++23
};
template<class T1, class T2, class U1, class U2, template<class> class TQual, template<class> class UQual>
@ -123,6 +133,9 @@ template <class T1, class T2>
void
swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y))); // constexpr in C++20
template<class T1, class T2>
constexpr void swap(const pair<T1, T2>& x, const pair<T1, T2>& y) noexcept(noexcept(x.swap(y))); // since C++23
struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
inline constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();

View File

@ -22,7 +22,7 @@
#include <type_traits>
#include "test_macros.h"
#include "types.h"
#include "copy_move_types.h"
// test constraints

View File

@ -22,7 +22,7 @@
#include <type_traits>
#include "test_macros.h"
#include "types.h"
#include "copy_move_types.h"
// test constraints

View File

@ -21,7 +21,7 @@
#include <type_traits>
#include "test_macros.h"
#include "types.h"
#include "copy_move_types.h"
static_assert(!std::is_assignable_v<const std::tuple<int>&, const std::tuple<int>&>);
static_assert(std::is_assignable_v<const std::tuple<int&>&, const std::tuple<int&>&>);

View File

@ -21,7 +21,7 @@
#include <type_traits>
#include "test_macros.h"
#include "types.h"
#include "copy_move_types.h"
static_assert(!std::is_assignable_v<const std::tuple<int>&, std::tuple<int>&&>);
static_assert(std::is_assignable_v<const std::tuple<int&>&, std::tuple<int&>&&>);

View File

@ -23,7 +23,7 @@
#include <utility>
#include "test_macros.h"
#include "types.h"
#include "copy_move_types.h"
// test constraints

View File

@ -23,7 +23,7 @@
#include <utility>
#include "test_macros.h"
#include "types.h"
#include "copy_move_types.h"
// test constraints

View File

@ -1,138 +0,0 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LIBCXX_TEST_STD_UTILITIES_TUPLE_ASSIGN_TYPES_H
#define LIBCXX_TEST_STD_UTILITIES_TUPLE_ASSIGN_TYPES_H
#include "test_allocator.h"
#include <type_traits>
struct CopyAssign {
int val;
constexpr CopyAssign() = default;
constexpr CopyAssign(int v) : val(v) {}
constexpr CopyAssign& operator=(const CopyAssign&) = default;
constexpr const CopyAssign& operator=(const CopyAssign&) const = delete;
constexpr CopyAssign& operator=(CopyAssign&&) = delete;
constexpr const CopyAssign& operator=(CopyAssign&&) const = delete;
};
struct ConstCopyAssign {
mutable int val;
constexpr ConstCopyAssign() = default;
constexpr ConstCopyAssign(int v) : val(v) {}
constexpr const ConstCopyAssign& operator=(const ConstCopyAssign& other) const {
val = other.val;
return *this;
}
constexpr ConstCopyAssign& operator=(const ConstCopyAssign&) = delete;
constexpr ConstCopyAssign& operator=(ConstCopyAssign&&) = delete;
constexpr const ConstCopyAssign& operator=(ConstCopyAssign&&) const = delete;
};
struct MoveAssign {
int val;
constexpr MoveAssign() = default;
constexpr MoveAssign(int v) : val(v) {}
constexpr MoveAssign& operator=(MoveAssign&&) = default;
constexpr MoveAssign& operator=(const MoveAssign&) = delete;
constexpr const MoveAssign& operator=(const MoveAssign&) const = delete;
constexpr const MoveAssign& operator=(MoveAssign&&) const = delete;
};
struct ConstMoveAssign {
mutable int val;
constexpr ConstMoveAssign() = default;
constexpr ConstMoveAssign(int v) : val(v) {}
constexpr const ConstMoveAssign& operator=(ConstMoveAssign&& other) const {
val = other.val;
return *this;
}
constexpr ConstMoveAssign& operator=(const ConstMoveAssign&) = delete;
constexpr const ConstMoveAssign& operator=(const ConstMoveAssign&) const = delete;
constexpr ConstMoveAssign& operator=(ConstMoveAssign&&) = delete;
};
template <class T>
struct AssignableFrom {
T v;
constexpr AssignableFrom() = default;
template <class U>
constexpr AssignableFrom(U&& u)
requires std::is_constructible_v<T, U&&>
: v(std::forward<U>(u)) {}
constexpr AssignableFrom& operator=(const T& t)
requires std::is_copy_assignable_v<T>
{
v = t;
return *this;
}
constexpr AssignableFrom& operator=(T&& t)
requires std::is_move_assignable_v<T>
{
v = std::move(t);
return *this;
}
constexpr const AssignableFrom& operator=(const T& t) const
requires std::is_assignable_v<const T&, const T&>
{
v = t;
return *this;
}
constexpr const AssignableFrom& operator=(T&& t) const
requires std::is_assignable_v<const T&, T&&>
{
v = std::move(t);
return *this;
}
};
struct TracedAssignment {
int copyAssign = 0;
mutable int constCopyAssign = 0;
int moveAssign = 0;
mutable int constMoveAssign = 0;
constexpr TracedAssignment() = default;
constexpr TracedAssignment& operator=(const TracedAssignment&) {
copyAssign++;
return *this;
}
constexpr const TracedAssignment& operator=(const TracedAssignment&) const {
constCopyAssign++;
return *this;
}
constexpr TracedAssignment& operator=(TracedAssignment&&) {
moveAssign++;
return *this;
}
constexpr const TracedAssignment& operator=(TracedAssignment&&) const {
constMoveAssign++;
return *this;
}
};
#endif

View File

@ -25,7 +25,7 @@
#include <tuple>
#include <utility>
#include "convert_types.h"
#include "copy_move_types.h"
#include "test_allocator.h"
// test constraints

View File

@ -31,7 +31,7 @@
#include <cassert>
#include <tuple>
#include "convert_types.h"
#include "copy_move_types.h"
#include "test_allocator.h"
#include "test_macros.h"

View File

@ -31,7 +31,7 @@
#include <cassert>
#include <tuple>
#include "convert_types.h"
#include "copy_move_types.h"
#include "test_allocator.h"
#include "test_macros.h"

View File

@ -24,7 +24,7 @@
#include <tuple>
#include <utility>
#include "convert_types.h"
#include "copy_move_types.h"
#include "test_allocator.h"
// test constraints

View File

@ -23,7 +23,7 @@
#include <tuple>
#include <utility>
#include "convert_types.h"
#include "copy_move_types.h"
// test constraints
// sizeof...(Types) == 2

View File

@ -30,7 +30,7 @@
#include <cassert>
#include <tuple>
#include "convert_types.h"
#include "copy_move_types.h"
#include "test_macros.h"
// test: The expression inside explicit is equivalent to:

View File

@ -29,7 +29,7 @@
#include <cassert>
#include <tuple>
#include "convert_types.h"
#include "copy_move_types.h"
#include "test_macros.h"
// test: The expression inside explicit is equivalent to:

View File

@ -23,7 +23,7 @@
#include <tuple>
#include <utility>
#include "convert_types.h"
#include "copy_move_types.h"
// test constraints
// sizeof...(Types) == 2

View File

@ -0,0 +1,87 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <utility>
// template <class T1, class T2> struct pair
// template<class U1, class U2> constexpr
// const pair& operator=(const pair<U1, U2>& p) const;
#include <cassert>
#include <utility>
#include "test_macros.h"
#include "copy_move_types.h"
// Constraints:
// is_assignable_v<const first_type&, const U1&> is true, and
// is_assignable_v<const second_type&, const U2&> is true.
// clang-format off
static_assert( std::is_assignable_v<const std::pair<int&, int&>&,
const std::pair<long&, long&>&>);
static_assert(!std::is_assignable_v<const std::pair<int, int>&,
const std::pair<long, long>&>);
static_assert(!std::is_assignable_v<const std::pair<int, int&>&,
const std::pair<long, long&>&>);
static_assert(!std::is_assignable_v<const std::pair<int&, int>&,
const std::pair<long&, long>&>);
static_assert(std::is_assignable_v<
const std::pair<AssignableFrom<ConstCopyAssign>, AssignableFrom<ConstCopyAssign>>&,
const std::pair<ConstCopyAssign, ConstCopyAssign>&>);
static_assert(!std::is_assignable_v<
const std::pair<AssignableFrom<CopyAssign>, AssignableFrom<CopyAssign>>&,
const std::pair<CopyAssign, CopyAssign>&>);
// clang-format on
constexpr bool test() {
// reference types
{
int i1 = 1;
int i2 = 2;
long j1 = 3;
long j2 = 4;
const std::pair<int&, int&> p1{i1, i2};
const std::pair<long&, long&> p2{j1, j2};
p2 = p1;
assert(p2.first == 1);
assert(p2.second == 2);
}
// user defined const copy assignment
{
const std::pair<ConstCopyAssign, ConstCopyAssign> p1{1, 2};
const std::pair<AssignableFrom<ConstCopyAssign>, AssignableFrom<ConstCopyAssign>> p2{3, 4};
p2 = p1;
assert(p2.first.v.val == 1);
assert(p2.second.v.val == 2);
}
// The correct assignment operator of the underlying type is used
{
std::pair<TracedAssignment, TracedAssignment> t1{};
const std::pair<AssignableFrom<TracedAssignment>, AssignableFrom<TracedAssignment>> t2{};
t2 = t1;
assert(t2.first.v.constCopyAssign == 1);
assert(t2.second.v.constCopyAssign == 1);
}
return true;
}
int main(int, const char**) {
test();
// gcc cannot have mutable member in constant expression
#if !defined(TEST_COMPILER_GCC)
static_assert(test());
#endif
}

View File

@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <utility>
// template <class T1, class T2> struct pair
// constexpr const pair& operator=(const pair& p) const;
#include <cassert>
#include <utility>
#include "test_macros.h"
#include "copy_move_types.h"
// Constraints:
// is_copy_assignable<const first_type> is true and
// is_copy_assignable<const second_type> is true.
// clang-format off
static_assert(std::is_assignable_v<const std::pair<int&, int&>&,
const std::pair<int&, int&>&>);
static_assert(!std::is_assignable_v<const std::pair<int, int>&,
const std::pair<int, int>&>);
static_assert(!std::is_assignable_v<const std::pair<int, int&>&,
const std::pair<int, int&>&>);
static_assert(!std::is_assignable_v<const std::pair<int&, int>&,
const std::pair<int&, int>&>);
static_assert(std::is_assignable_v<const std::pair<ConstCopyAssign, ConstCopyAssign>&,
const std::pair<ConstCopyAssign, ConstCopyAssign>&>);
static_assert(!std::is_assignable_v<const std::pair<CopyAssign, CopyAssign>&,
const std::pair<CopyAssign, CopyAssign>&>);
// clang-format on
constexpr bool test() {
// reference types
{
int i1 = 1;
int i2 = 2;
double d1 = 3.0;
double d2 = 5.0;
const std::pair<int&, double&> p1{i1, d1};
const std::pair<int&, double&> p2{i2, d2};
p2 = p1;
assert(p2.first == 1);
assert(p2.second == 3.0);
}
// user defined const copy assignment
{
const std::pair<ConstCopyAssign, ConstCopyAssign> p1{1, 2};
const std::pair<ConstCopyAssign, ConstCopyAssign> p2{3, 4};
p2 = p1;
assert(p2.first.val == 1);
assert(p2.second.val == 2);
}
// The correct assignment operator of the underlying type is used
{
std::pair<TracedAssignment, const TracedAssignment> t1{};
const std::pair<TracedAssignment, const TracedAssignment> t2{};
t2 = t1;
assert(t2.first.constCopyAssign == 1);
assert(t2.second.constCopyAssign == 1);
}
return true;
}
int main(int, const char**) {
test();
// gcc cannot have mutable member in constant expression
#if !defined(TEST_COMPILER_GCC)
static_assert(test());
#endif
}

View File

@ -0,0 +1,87 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <utility>
// template <class T1, class T2> struct pair
// template <class U1, class U2>
// constexpr const pair& operator=(pair<U1, U2>&& p) const;
#include <cassert>
#include <utility>
#include "test_macros.h"
#include "copy_move_types.h"
// Constraints:
// is_assignable<const first_type&, U1> is true and
// is_assignable<const second_type&, U2> is true.
// clang-format off
static_assert( std::is_assignable_v<const std::pair<int&&, int&&>&,
std::pair<long&&, long&&>&&>);
static_assert(!std::is_assignable_v<const std::pair<int, int>&,
std::pair<long, long>&&>);
static_assert(!std::is_assignable_v<const std::pair<int, int&&>&,
std::pair<long, long&&>&&>);
static_assert(!std::is_assignable_v<const std::pair<int&&, int>&,
std::pair<long&&, long>&&>);
static_assert(std::is_assignable_v<
const std::pair<AssignableFrom<ConstMoveAssign>, AssignableFrom<ConstMoveAssign>>&,
std::pair<ConstMoveAssign, ConstMoveAssign>&&>);
static_assert(!std::is_assignable_v<
const std::pair<AssignableFrom<MoveAssign>, AssignableFrom<MoveAssign>>&,
std::pair<MoveAssign, MoveAssign>&&>);
// clang-format on
constexpr bool test() {
// reference types
{
int i1 = 1;
int i2 = 2;
long j1 = 3;
long j2 = 4;
std::pair<int&&, int&&> p1{std::move(i1), std::move(i2)};
const std::pair<long&&, long&&> p2{std::move(j1), std::move(j2)};
p2 = std::move(p1);
assert(p2.first == 1);
assert(p2.second == 2);
}
// user defined const move assignment
{
std::pair<ConstMoveAssign, ConstMoveAssign> p1{1, 2};
const std::pair<AssignableFrom<ConstMoveAssign>, AssignableFrom<ConstMoveAssign>> p2{3, 4};
p2 = std::move(p1);
assert(p2.first.v.val == 1);
assert(p2.second.v.val == 2);
}
// The correct assignment operator of the underlying type is used
{
std::pair<TracedAssignment, TracedAssignment> t1{};
const std::pair<AssignableFrom<TracedAssignment>, AssignableFrom<TracedAssignment>> t2{};
t2 = std::move(t1);
assert(t2.first.v.constMoveAssign == 1);
assert(t2.second.v.constMoveAssign == 1);
}
return true;
}
int main(int, const char**) {
test();
// gcc cannot have mutable member in constant expression
#if !defined(TEST_COMPILER_GCC)
static_assert(test());
#endif
}

View File

@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <utility>
// template <class T1, class T2> struct pair
// constexpr const pair& operator=(pair&& p) const;
#include <cassert>
#include <utility>
#include "test_macros.h"
#include "copy_move_types.h"
// Constraints:
// is_assignable<const first_type&, first_type> is true and
// is_assignable<const second_type&, second_type> is true.
// clang-format off
static_assert(std::is_assignable_v<const std::pair<int&&, int&&>&,
std::pair<int&&, int&&>&&>);
static_assert(!std::is_assignable_v<const std::pair<int, int>&,
std::pair<int, int>&&>);
static_assert(!std::is_assignable_v<const std::pair<int, int&&>&,
std::pair<int, int&&>&&>);
static_assert(!std::is_assignable_v<const std::pair<int&&, int>&,
std::pair<int&&, int>&&>);
static_assert(std::is_assignable_v<const std::pair<ConstMoveAssign, ConstMoveAssign>&,
std::pair<ConstMoveAssign, ConstMoveAssign>&&>);
static_assert(!std::is_assignable_v<const std::pair<MoveAssign, MoveAssign>&,
std::pair<MoveAssign, MoveAssign>&&>);
// clang-format on
constexpr bool test() {
// reference types
{
int i1 = 1;
int i2 = 2;
double d1 = 3.0;
double d2 = 5.0;
std::pair<int&&, double&&> p1{std::move(i1), std::move(d1)};
const std::pair<int&&, double&&> p2{std::move(i2), std::move(d2)};
p2 = std::move(p1);
assert(p2.first == 1);
assert(p2.second == 3.0);
}
// user defined const move assignment
{
std::pair<ConstMoveAssign, ConstMoveAssign> p1{1, 2};
const std::pair<ConstMoveAssign, ConstMoveAssign> p2{3, 4};
p2 = std::move(p1);
assert(p2.first.val == 1);
assert(p2.second.val == 2);
}
// The correct assignment operator of the underlying type is used
{
std::pair<TracedAssignment, const TracedAssignment> t1{};
const std::pair<TracedAssignment, const TracedAssignment> t2{};
t2 = std::move(t1);
assert(t2.first.constMoveAssign == 1);
assert(t2.second.constCopyAssign == 1);
}
return true;
}
int main(int, const char**) {
test();
// gcc cannot have mutable member in constant expression
#if !defined(TEST_COMPILER_GCC)
static_assert(test());
#endif
}

View File

@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <utility>
// template <class T1, class T2> struct pair
// template <class U1, class U2>
// constexpr explicit(see below) pair(const pair<U1, U2>&& p);
#include <cassert>
#include <utility>
#include "copy_move_types.h"
#include "test_macros.h"
// Constraints:
// is_constructible_v<T1, decltype(get<0>(FWD(p)))> is true and
// is_constructible_v<T2, decltype(get<1>(FWD(p)))> is true.
struct X {};
struct Y {};
struct NotConvertibleToXorY {};
static_assert(std::is_constructible_v<std::pair<X, Y>, const std::pair<X, Y>&&>);
static_assert(!std::is_constructible_v<std::pair<X, Y>, const std::pair<NotConvertibleToXorY, Y>&&>);
static_assert(!std::is_constructible_v<std::pair<X, Y>, const std::pair<X, NotConvertibleToXorY>&&>);
static_assert(!std::is_constructible_v<std::pair<X, Y>, const std::pair<NotConvertibleToXorY, NotConvertibleToXorY>&&>);
// The expression inside explicit is equivalent to:
// !is_convertible_v<decltype(get<0>(FWD(p))), first_type> ||
// !is_convertible_v<decltype(get<1>(FWD(p))), second_type>.
// clang-format off
static_assert( std::is_convertible_v<const std::pair<X, Y>&&,
std::pair<ConvertibleFrom<X>, ConvertibleFrom<Y>>>);
static_assert(!std::is_convertible_v<const std::pair<X, Y>&&,
std::pair<ConvertibleFrom<X>, ExplicitConstructibleFrom<Y>>>);
static_assert(!std::is_convertible_v<const std::pair<X, Y>&&,
std::pair<ExplicitConstructibleFrom<X>, ConvertibleFrom<Y>>>);
static_assert(!std::is_convertible_v<const std::pair<X, Y>&&,
std::pair<ExplicitConstructibleFrom<X>, ExplicitConstructibleFrom<Y>>>);
// clang-format on
constexpr bool test() {
// simple case: init pair<const T&&, const U&&> from const pair<T, U>&&
{
const std::pair<int, int> p1{1, 2};
std::pair<const int&&, const int&&> p2{std::move(p1)};
assert(&(p2.first) == &(p1.first));
assert(&(p2.second) == &(p1.second));
}
// test implicit conversions.
{
const std::pair<ConstMove, int> p1{1, 2};
std::pair<ConvertibleFrom<ConstMove>, ConvertibleFrom<int>> p2 = std::move(p1);
assert(p2.first.v.val == 1);
assert(p2.second.v == 2);
}
// test explicit conversions.
{
const std::pair<ConstMove, int> p1{1, 2};
std::pair<ExplicitConstructibleFrom<ConstMove>, ExplicitConstructibleFrom<int>> p2{std::move(p1)};
assert(p2.first.v.val == 1);
assert(p2.second.v == 2);
}
// test correct constructors of underlying types are called
{
const std::pair<TracedCopyMove, TracedCopyMove> p1{};
std::pair<ConvertibleFrom<TracedCopyMove>, ConvertibleFrom<TracedCopyMove>> p2{std::move(p1)};
assert(constMoveCtrCalled(p2.first.v));
assert(constMoveCtrCalled(p2.second.v));
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,85 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <utility>
// template <class T1, class T2> struct pair
// template <class U1, class U2>
// constexpr explicit(see below) pair(pair<U1, U2>& p);
#include <cassert>
#include <utility>
#include "copy_move_types.h"
#include "test_macros.h"
// Constraints:
// is_constructible_v<T1, decltype(get<0>(FWD(p)))> is true and
// is_constructible_v<T2, decltype(get<1>(FWD(p)))> is true.
struct X {};
struct Y {};
struct NotConvertibleToXorY {};
// clang-format off
static_assert( std::is_constructible_v<std::pair<X, Y>, std::pair<X, Y>&>);
static_assert(!std::is_constructible_v<std::pair<X, Y>, std::pair<NotConvertibleToXorY, Y>&>);
static_assert(!std::is_constructible_v<std::pair<X, Y>, std::pair<X, NotConvertibleToXorY>&>);
static_assert(!std::is_constructible_v<std::pair<X, Y>, std::pair<NotConvertibleToXorY, NotConvertibleToXorY>&>);
// The expression inside explicit is equivalent to:
// !is_convertible_v<decltype(get<0>(FWD(p))), first_type> ||
// !is_convertible_v<decltype(get<1>(FWD(p))), second_type>.
static_assert( std::is_convertible_v<std::pair<X, Y>&, std::pair<ConvertibleFrom<X>, ConvertibleFrom<Y>>>);
static_assert(!std::is_convertible_v<std::pair<X, Y>&, std::pair<ConvertibleFrom<X>, ExplicitConstructibleFrom<Y>>>);
static_assert(!std::is_convertible_v<std::pair<X, Y>&, std::pair<ExplicitConstructibleFrom<X>, ConvertibleFrom<Y>>>);
static_assert(!std::is_convertible_v<std::pair<X, Y>&, std::pair<ExplicitConstructibleFrom<X>, ExplicitConstructibleFrom<Y>>>);
// clang-format on
constexpr bool test() {
// use case in zip. Init pair<T&, U&> from pair<T, U>&
{
std::pair<int, int> p1{1, 2};
std::pair<int&, int&> p2{p1};
assert(&(p2.first) == &(p1.first));
assert(&(p2.second) == &(p1.second));
}
// test implicit conversions.
{
std::pair<MutableCopy, int> p1{1, 2};
std::pair<ConvertibleFrom<MutableCopy>, ConvertibleFrom<int>> p2 = p1;
assert(p2.first.v.val == 1);
assert(p2.second.v == 2);
}
// test explicit conversions.
{
std::pair<MutableCopy, int> p1{1, 2};
std::pair<ExplicitConstructibleFrom<MutableCopy>, ExplicitConstructibleFrom<int>> p2{p1};
assert(p2.first.v.val == 1);
assert(p2.second.v == 2);
}
// test correct constructors of underlying types are called
{
std::pair<TracedCopyMove, TracedCopyMove> p1{};
std::pair<ConvertibleFrom<TracedCopyMove>, ConvertibleFrom<TracedCopyMove>> p2{p1};
assert(nonConstCopyCtrCalled(p2.first.v));
assert(nonConstCopyCtrCalled(p2.second.v));
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View File

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <utility>
// template <class T1, class T2> struct pair
// void swap(const pair& p) const;
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
#include <cassert>
#include <utility>
#include "test_macros.h"
// Remarks: The expression inside noexcept is equivalent to
// is_nothrow_swappable_v<const first_type> && is_nothrow_swappable_v<const second_type> for the second overload.
template <class T>
concept ConstMemberSwapNoexcept =
requires(const T& t1, const T& t2) {
{ t1.swap(t2) } noexcept;
};
template <bool canThrow>
struct SwapMayThrow {};
template <bool canThrow>
void swap(const SwapMayThrow<canThrow>&, const SwapMayThrow<canThrow>&) noexcept(!canThrow);
static_assert(ConstMemberSwapNoexcept<std::pair<SwapMayThrow<false>, SwapMayThrow<false>>>);
static_assert(!ConstMemberSwapNoexcept<std::pair<SwapMayThrow<true>, SwapMayThrow<false>>>);
static_assert(!ConstMemberSwapNoexcept<std::pair<SwapMayThrow<false>, SwapMayThrow<true>>>);
static_assert(!ConstMemberSwapNoexcept<std::pair<SwapMayThrow<true>, SwapMayThrow<true>>>);
struct ConstSwappable {
mutable int i;
friend constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); }
};
constexpr bool test() {
// user defined const swap
{
using P = std::pair<const ConstSwappable, const ConstSwappable>;
const P p1(ConstSwappable{0}, ConstSwappable{1});
const P p2(ConstSwappable{2}, ConstSwappable{3});
p1.swap(p2);
assert(p1.first.i == 2);
assert(p1.second.i == 3);
assert(p2.first.i == 0);
assert(p2.second.i == 1);
}
// pair of references
{
int i1 = 0, i2 = 1, i3 = 2, i4 = 3;
const std::pair<int&, int&> p1{i1, i2};
const std::pair<int&, int&> p2{i3, i4};
p1.swap(p2);
assert(p1.first == 2);
assert(p1.second == 3);
assert(p2.first == 0);
assert(p2.second == 1);
}
return true;
}
int main(int, char**) {
test();
// gcc cannot have mutable member in constant expression
#if !defined(TEST_COMPILER_GCC)
static_assert(test());
#endif
return 0;
}

View File

@ -0,0 +1,93 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// <utility>
// template <class T1, class T2>
// void swap(const pair<T1, T2>& x, const pair<T1, T2>& y) const noexcept(noexcept(x.swap(y)));;
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
#include <cassert>
#include <utility>
#include "test_macros.h"
// Constraints:
// For the second overload, is_swappable_v<const T1> is true and is_swappable_v<const T2> is true.
struct NonConstSwappable {
friend constexpr void swap(NonConstSwappable&, NonConstSwappable&);
};
struct ConstSwappable {
mutable int i;
friend constexpr void swap(const ConstSwappable& lhs, const ConstSwappable& rhs) { std::swap(lhs.i, rhs.i); }
};
static_assert(std::is_swappable_v<const std::pair<ConstSwappable, ConstSwappable>>);
static_assert(!std::is_swappable_v<const std::pair<NonConstSwappable, ConstSwappable>>);
static_assert(!std::is_swappable_v<const std::pair<ConstSwappable, NonConstSwappable>>);
static_assert(!std::is_swappable_v<const std::pair<NonConstSwappable, NonConstSwappable>>);
// noexcept(noexcept(x.swap(y)));
template <class T>
concept NonMemberSwapNoexcept =
requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};
template <bool canThrow>
struct SwapMayThrow {};
template <bool canThrow>
void swap(const SwapMayThrow<canThrow>&, const SwapMayThrow<canThrow>&) noexcept(!canThrow);
static_assert(NonMemberSwapNoexcept<const std::pair<SwapMayThrow<false>, SwapMayThrow<false>>>);
static_assert(!NonMemberSwapNoexcept<const std::pair<SwapMayThrow<true>, SwapMayThrow<false>>>);
static_assert(!NonMemberSwapNoexcept<const std::pair<SwapMayThrow<false>, SwapMayThrow<true>>>);
static_assert(!NonMemberSwapNoexcept<const std::pair<SwapMayThrow<true>, SwapMayThrow<true>>>);
constexpr bool test() {
// user defined const swap
{
using P = std::pair<const ConstSwappable, const ConstSwappable>;
const P p1(ConstSwappable{0}, ConstSwappable{1});
const P p2(ConstSwappable{2}, ConstSwappable{3});
using std::swap;
swap(p1, p2);
assert(p1.first.i == 2);
assert(p1.second.i == 3);
assert(p2.first.i == 0);
assert(p2.second.i == 1);
}
// pair of references
{
int i1 = 0, i2 = 1, i3 = 2, i4 = 3;
const std::pair<int&, int&> p1{i1, i2};
const std::pair<int&, int&> p2{i3, i4};
using std::swap;
swap(p1, p2);
assert(p1.first == 2);
assert(p1.second == 3);
assert(p2.first == 0);
assert(p2.second == 1);
}
return true;
}
int main(int, char**) {
test();
// gcc cannot have mutable member in constant expression
#if !defined(TEST_COMPILER_GCC)
static_assert(test());
#endif
return 0;
}

View File

@ -10,6 +10,9 @@
#include "test_allocator.h"
#include <type_traits>
#include <tuple>
// Types that can be used to test copy/move operations
struct MutableCopy {
int val;
@ -215,4 +218,127 @@ void conversion_test(T);
template <class T, class... Args>
concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
struct CopyAssign {
int val;
constexpr CopyAssign() = default;
constexpr CopyAssign(int v) : val(v) {}
constexpr CopyAssign& operator=(const CopyAssign&) = default;
constexpr const CopyAssign& operator=(const CopyAssign&) const = delete;
constexpr CopyAssign& operator=(CopyAssign&&) = delete;
constexpr const CopyAssign& operator=(CopyAssign&&) const = delete;
};
struct ConstCopyAssign {
mutable int val;
constexpr ConstCopyAssign() = default;
constexpr ConstCopyAssign(int v) : val(v) {}
constexpr const ConstCopyAssign& operator=(const ConstCopyAssign& other) const {
val = other.val;
return *this;
}
constexpr ConstCopyAssign& operator=(const ConstCopyAssign&) = delete;
constexpr ConstCopyAssign& operator=(ConstCopyAssign&&) = delete;
constexpr const ConstCopyAssign& operator=(ConstCopyAssign&&) const = delete;
};
struct MoveAssign {
int val;
constexpr MoveAssign() = default;
constexpr MoveAssign(int v) : val(v) {}
constexpr MoveAssign& operator=(MoveAssign&&) = default;
constexpr MoveAssign& operator=(const MoveAssign&) = delete;
constexpr const MoveAssign& operator=(const MoveAssign&) const = delete;
constexpr const MoveAssign& operator=(MoveAssign&&) const = delete;
};
struct ConstMoveAssign {
mutable int val;
constexpr ConstMoveAssign() = default;
constexpr ConstMoveAssign(int v) : val(v) {}
constexpr const ConstMoveAssign& operator=(ConstMoveAssign&& other) const {
val = other.val;
return *this;
}
constexpr ConstMoveAssign& operator=(const ConstMoveAssign&) = delete;
constexpr const ConstMoveAssign& operator=(const ConstMoveAssign&) const = delete;
constexpr ConstMoveAssign& operator=(ConstMoveAssign&&) = delete;
};
template <class T>
struct AssignableFrom {
T v;
constexpr AssignableFrom() = default;
template <class U>
constexpr AssignableFrom(U&& u)
requires std::is_constructible_v<T, U&&>
: v(std::forward<U>(u)) {}
constexpr AssignableFrom& operator=(const T& t)
requires std::is_copy_assignable_v<T>
{
v = t;
return *this;
}
constexpr AssignableFrom& operator=(T&& t)
requires std::is_move_assignable_v<T>
{
v = std::move(t);
return *this;
}
constexpr const AssignableFrom& operator=(const T& t) const
requires std::is_assignable_v<const T&, const T&>
{
v = t;
return *this;
}
constexpr const AssignableFrom& operator=(T&& t) const
requires std::is_assignable_v<const T&, T&&>
{
v = std::move(t);
return *this;
}
};
struct TracedAssignment {
int copyAssign = 0;
mutable int constCopyAssign = 0;
int moveAssign = 0;
mutable int constMoveAssign = 0;
constexpr TracedAssignment() = default;
constexpr TracedAssignment& operator=(const TracedAssignment&) {
copyAssign++;
return *this;
}
constexpr const TracedAssignment& operator=(const TracedAssignment&) const {
constCopyAssign++;
return *this;
}
constexpr TracedAssignment& operator=(TracedAssignment&&) {
moveAssign++;
return *this;
}
constexpr const TracedAssignment& operator=(TracedAssignment&&) const {
constMoveAssign++;
return *this;
}
};
#endif