зеркало из https://github.com/microsoft/STL.git
P2165R4: Compatibility Between `tuple`, `pair`, And tuple-like Objects (changes to `pair` only) (#3323)
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Родитель
31defd3719
Коммит
10722961ab
|
@ -429,6 +429,9 @@ namespace ranges {
|
|||
|
||||
_EXPORT_STD using ranges::get;
|
||||
|
||||
template <class _It, class _Se, ranges::subrange_kind _Ki>
|
||||
inline constexpr bool _Is_subrange_v<ranges::subrange<_It, _Se, _Ki>> = true;
|
||||
|
||||
template <class _It, class _Se, ranges::subrange_kind _Ki>
|
||||
struct tuple_size<ranges::subrange<_It, _Se, _Ki>> : integral_constant<size_t, 2> {};
|
||||
|
||||
|
|
|
@ -2713,11 +2713,6 @@ namespace ranges {
|
|||
inline constexpr bool enable_borrowed_range<take_view<_Rng>> = enable_borrowed_range<_Rng>;
|
||||
|
||||
namespace views {
|
||||
template <class>
|
||||
inline constexpr bool _Is_subrange = false;
|
||||
template <class _It, class _Se, subrange_kind _Ki>
|
||||
inline constexpr bool _Is_subrange<subrange<_It, _Se, _Ki>> = true;
|
||||
|
||||
template <class _Rng>
|
||||
concept _Random_sized_range = random_access_range<_Rng> && sized_range<_Rng>;
|
||||
|
||||
|
@ -2745,7 +2740,7 @@ namespace ranges {
|
|||
} else if constexpr (_Random_sized_range<_Ty> && _Is_specialization_v<_Ty, iota_view>) {
|
||||
return {_St::_Reconstruct_iota_view,
|
||||
noexcept(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()))};
|
||||
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange<_Ty>) {
|
||||
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
|
||||
return {_St::_Reconstruct_subrange,
|
||||
noexcept(subrange(_RANGES begin(_STD declval<_Rng&>()),
|
||||
_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>())))};
|
||||
|
@ -3121,7 +3116,7 @@ namespace ranges {
|
|||
return {_St::_Reconstruct_span, true};
|
||||
} else if constexpr (_Is_specialization_v<_Ty, basic_string_view>) {
|
||||
return {_St::_Reconstruct_other, true};
|
||||
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange<_Ty>) {
|
||||
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
|
||||
if constexpr (sized_sentinel_for<sentinel_t<_Ty>, iterator_t<_Ty>>) {
|
||||
return {_St::_Reconstruct_subrange,
|
||||
noexcept(_Ty(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()),
|
||||
|
|
|
@ -222,9 +222,6 @@ struct _Span_extent_type<_Ty, dynamic_extent> {
|
|||
size_t _Mysize{0};
|
||||
};
|
||||
|
||||
_EXPORT_STD template <class _Ty, size_t _Size>
|
||||
class array;
|
||||
|
||||
_EXPORT_STD template <class _Ty, size_t _Extent>
|
||||
class span;
|
||||
|
||||
|
@ -242,12 +239,6 @@ inline constexpr bool _Is_span_v = false;
|
|||
template <class _Ty, size_t _Extent>
|
||||
inline constexpr bool _Is_span_v<span<_Ty, _Extent>> = true;
|
||||
|
||||
template <class>
|
||||
inline constexpr bool _Is_std_array_v = false;
|
||||
|
||||
template <class _Ty, size_t _Size>
|
||||
inline constexpr bool _Is_std_array_v<array<_Ty, _Size>> = true;
|
||||
|
||||
// clang-format off
|
||||
template <class _It, class _Ty>
|
||||
concept _Span_compatible_iterator = contiguous_iterator<_It>
|
||||
|
|
|
@ -179,9 +179,6 @@ struct _Alloc_unpack_tuple_t {
|
|||
explicit _Alloc_unpack_tuple_t() = default;
|
||||
}; // tag type to disambiguate construction (from an allocator and unpacking a tuple/pair)
|
||||
|
||||
_EXPORT_STD template <class... _Types>
|
||||
class tuple;
|
||||
|
||||
template <>
|
||||
class tuple<> { // empty tuple
|
||||
public:
|
||||
|
@ -824,21 +821,6 @@ _NODISCARD constexpr tuple<_Types&&...> forward_as_tuple(_Types&&... _Args) noex
|
|||
return tuple<_Types&&...>(_STD forward<_Types>(_Args)...);
|
||||
}
|
||||
|
||||
_EXPORT_STD template <class _Ty, size_t _Size>
|
||||
class array;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr _Ty& get(array<_Ty, _Size>& _Arr) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr const _Ty& get(const array<_Ty, _Size>& _Arr) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr _Ty&& get(array<_Ty, _Size>&& _Arr) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr const _Ty&& get(const array<_Ty, _Size>&& _Arr) noexcept;
|
||||
|
||||
template <class _Ty, class _Kx_arg, class _Ix_arg, size_t _Ix_next, class... _Sequences>
|
||||
struct _Tuple_cat2;
|
||||
|
||||
|
|
134
stl/inc/utility
134
stl/inc/utility
|
@ -134,12 +134,87 @@ struct uses_allocator : _Has_allocator_type<_Ty, _Alloc>::type {
|
|||
_EXPORT_STD template <class _Ty, class _Alloc>
|
||||
_INLINE_VAR constexpr bool uses_allocator_v = uses_allocator<_Ty, _Alloc>::value;
|
||||
|
||||
_EXPORT_STD template <class...>
|
||||
_EXPORT_STD template <class... _Types>
|
||||
class tuple;
|
||||
|
||||
_EXPORT_STD template <class _Ty1, class _Ty2>
|
||||
struct pair;
|
||||
|
||||
_EXPORT_STD template <class _Ty, size_t _Size>
|
||||
class array;
|
||||
|
||||
_EXPORT_STD template <class _Tuple>
|
||||
struct tuple_size;
|
||||
|
||||
_EXPORT_STD template <class _Ty>
|
||||
_INLINE_VAR constexpr size_t tuple_size_v = tuple_size<_Ty>::value;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class _Tuple>
|
||||
struct tuple_element;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class _Tuple>
|
||||
using tuple_element_t = typename tuple_element<_Index, _Tuple>::type;
|
||||
|
||||
_EXPORT_STD /* TRANSITION, VSO-1538698 */ template <size_t _Index, class... _Types>
|
||||
_NODISCARD constexpr auto&& _Tuple_get(tuple<_Types...>&& _Tuple) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class... _Types>
|
||||
_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class... _Types>
|
||||
_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class... _Types>
|
||||
_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class... _Types>
|
||||
_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr _Ty& get(array<_Ty, _Size>& _Arr) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr const _Ty& get(const array<_Ty, _Size>& _Arr) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr _Ty&& get(array<_Ty, _Size>&& _Arr) noexcept;
|
||||
|
||||
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
|
||||
_NODISCARD constexpr const _Ty&& get(const array<_Ty, _Size>&& _Arr) noexcept;
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Different_from = (!same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>);
|
||||
|
||||
template <class>
|
||||
inline constexpr bool _Is_std_array_v = false;
|
||||
|
||||
template <class _Ty, size_t _Size>
|
||||
inline constexpr bool _Is_std_array_v<array<_Ty, _Size>> = true;
|
||||
|
||||
template <class>
|
||||
inline constexpr bool _Is_subrange_v = false;
|
||||
|
||||
#if _HAS_CXX23
|
||||
template <class _Ty>
|
||||
inline constexpr bool _Tuple_like_impl =
|
||||
_Is_specialization_v<_Ty, tuple> || _Is_specialization_v<_Ty, pair> || _Is_std_array_v<_Ty> || _Is_subrange_v<_Ty>;
|
||||
|
||||
template <class _Ty>
|
||||
concept _Tuple_like = _Tuple_like_impl<remove_cvref_t<_Ty>>;
|
||||
|
||||
template <class _Ty>
|
||||
concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v<remove_cvref_t<_Ty>> == 2;
|
||||
|
||||
#ifdef __clang__ // TRANSITION, LLVM-59827
|
||||
template <class _PairLike, class _Ty1, class _Ty2>
|
||||
concept _Can_construct_from_pair_like =
|
||||
_Pair_like<_PairLike> && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))>
|
||||
&& is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>;
|
||||
#endif // __clang__
|
||||
#endif // _HAS_CXX23
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
_EXPORT_STD template <class _Ty1, class _Ty2>
|
||||
struct pair { // store a pair of values
|
||||
using first_type = _Ty1;
|
||||
|
@ -207,6 +282,22 @@ struct pair { // store a pair of values
|
|||
pair(const pair<_Other1, _Other2>&& _Right) noexcept(is_nothrow_constructible_v<_Ty1, const _Other1>&&
|
||||
is_nothrow_constructible_v<_Ty2, const _Other2>) // strengthened
|
||||
: first(_STD forward<const _Other1>(_Right.first)), second(_STD forward<const _Other2>(_Right.second)) {}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
#ifdef __clang__ // TRANSITION, LLVM-59827
|
||||
template <class _Other, enable_if_t<_Can_construct_from_pair_like<_Other, _Ty1, _Ty2>, int> = 0>
|
||||
#else // ^^^ workaround / no workaround vvv
|
||||
template <_Pair_like _Other>
|
||||
requires conjunction_v<is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>,
|
||||
is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>>
|
||||
#endif // __clang__
|
||||
constexpr explicit(!conjunction_v<is_convertible<decltype(_STD get<0>(_STD declval<_Other>())), _Ty1>,
|
||||
is_convertible<decltype(_STD get<1>(_STD declval<_Other>())), _Ty2>>)
|
||||
pair(_Other&& _Right) noexcept(is_nothrow_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>&&
|
||||
is_nothrow_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) // strengthened
|
||||
: first(_STD get<0>(_STD forward<_Other>(_Right))), second(_STD get<1>(_STD forward<_Other>(_Right))) {
|
||||
}
|
||||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX23
|
||||
|
||||
template <class _Tuple1, class _Tuple2, size_t... _Indexes1, size_t... _Indexes2>
|
||||
|
@ -318,6 +409,32 @@ struct pair { // store a pair of values
|
|||
second = _STD forward<_Other2>(_Right.second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
template <_Pair_like _Other>
|
||||
requires _Different_from<_Other, pair> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
|
||||
&& is_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
|
||||
&& is_assignable_v<_Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>
|
||||
constexpr pair& operator=(_Other&& _Right) noexcept(
|
||||
is_nothrow_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>&&
|
||||
is_nothrow_assignable_v<_Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>) /* strengthened */ {
|
||||
first = _STD get<0>(_STD forward<_Other>(_Right));
|
||||
second = _STD get<1>(_STD forward<_Other>(_Right));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <_Pair_like _Other>
|
||||
requires _Different_from<_Other, pair> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
|
||||
&& is_assignable_v<const _Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
|
||||
&& is_assignable_v<const _Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>
|
||||
constexpr const pair& operator=(_Other&& _Right) const noexcept(
|
||||
is_nothrow_assignable_v<const _Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>&&
|
||||
is_nothrow_assignable_v<const _Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>) /* strengthened */ {
|
||||
first = _STD get<0>(_STD forward<_Other>(_Right));
|
||||
second = _STD get<1>(_STD forward<_Other>(_Right));
|
||||
return *this;
|
||||
}
|
||||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX23
|
||||
|
||||
_CONSTEXPR20 void swap(pair& _Right) noexcept(
|
||||
|
@ -469,9 +586,6 @@ namespace _CXX20_DEPRECATE_REL_OPS rel_ops {
|
|||
}
|
||||
} // namespace _CXX20_DEPRECATE_REL_OPS rel_ops
|
||||
|
||||
_EXPORT_STD template <class _Tuple>
|
||||
struct tuple_size;
|
||||
|
||||
template <class _Tuple, class = void>
|
||||
struct _Tuple_size_sfinae {}; // selected when tuple_size<_Tuple>::value isn't well-formed
|
||||
|
||||
|
@ -488,12 +602,6 @@ struct _CXX20_DEPRECATE_VOLATILE tuple_size<volatile _Tuple> : _Tuple_size_sfina
|
|||
template <class _Tuple>
|
||||
struct _CXX20_DEPRECATE_VOLATILE tuple_size<const volatile _Tuple> : _Tuple_size_sfinae<_Tuple> {}; // ignore cv
|
||||
|
||||
_EXPORT_STD template <class _Ty>
|
||||
_INLINE_VAR constexpr size_t tuple_size_v = tuple_size<_Ty>::value;
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class _Tuple>
|
||||
struct tuple_element;
|
||||
|
||||
template <size_t _Index, class _Tuple>
|
||||
struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const _Tuple> : tuple_element<_Index, _Tuple> {
|
||||
using _Mybase = tuple_element<_Index, _Tuple>;
|
||||
|
@ -514,12 +622,6 @@ struct _CXX20_DEPRECATE_VOLATILE _MSVC_KNOWN_SEMANTICS tuple_element<_Index, con
|
|||
using type = add_cv_t<typename _Mybase::type>;
|
||||
};
|
||||
|
||||
_EXPORT_STD template <size_t _Index, class _Tuple>
|
||||
using tuple_element_t = typename tuple_element<_Index, _Tuple>::type;
|
||||
|
||||
_EXPORT_STD template <class _Ty, size_t _Size>
|
||||
class array;
|
||||
|
||||
template <class _Ty, size_t _Size>
|
||||
struct tuple_size<array<_Ty, _Size>> : integral_constant<size_t, _Size> {}; // size of array
|
||||
|
||||
|
|
|
@ -1755,9 +1755,6 @@ _NODISCARD constexpr const _Elem* data(initializer_list<_Elem> _Ilist) noexcept
|
|||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
template <class _Ty1, class _Ty2>
|
||||
concept _Different_from = (!same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>);
|
||||
|
||||
#if _HAS_CXX23
|
||||
_EXPORT_STD template <indirectly_readable _Ty>
|
||||
using iter_const_reference_t = common_reference_t<const iter_value_t<_Ty>&&, iter_reference_t<_Ty>>;
|
||||
|
|
|
@ -322,7 +322,7 @@
|
|||
// P2077R3 Heterogeneous Erasure Overloads For Associative Containers
|
||||
// P2136R3 invoke_r()
|
||||
// P2165R4 Compatibility Between tuple, pair, And tuple-like Objects
|
||||
// (changes to views::zip only)
|
||||
// (changes to views::zip and pair only)
|
||||
// P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr
|
||||
// P2186R2 Removing Garbage Collection Support
|
||||
// P2273R3 constexpr unique_ptr
|
||||
|
|
|
@ -551,6 +551,7 @@ tests\P1899R3_views_stride_death
|
|||
tests\P1951R1_default_arguments_pair_forward_ctor
|
||||
tests\P2136R3_invoke_r
|
||||
tests\P2162R2_std_visit_for_derived_classes_from_variant
|
||||
tests\P2165R4_tuple_like_pair
|
||||
tests\P2231R1_complete_constexpr_optional_variant
|
||||
tests\P2273R3_constexpr_unique_ptr
|
||||
tests\P2278R4_basic_const_iterator
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_latest_matrix.lst
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct TmpInt {
|
||||
constexpr TmpInt() : TmpInt(0) {}
|
||||
constexpr TmpInt(int v) : val{v} {}
|
||||
|
||||
constexpr TmpInt(const TmpInt&) = default;
|
||||
constexpr TmpInt(TmpInt&& other) : val{exchange(other.val, -1)} {}
|
||||
|
||||
constexpr TmpInt& operator=(const TmpInt&) = default;
|
||||
constexpr TmpInt& operator=(TmpInt&& other) {
|
||||
if (this != &other) {
|
||||
val = exchange(other.val, -1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int val;
|
||||
constexpr bool operator==(const TmpInt&) const = default;
|
||||
};
|
||||
|
||||
template <template <class> class PairLike>
|
||||
constexpr bool test_pair_like_constructor() {
|
||||
// Test pair(pair-like) constructor with PairLike<int>&
|
||||
static_assert(constructible_from<pair<int, int>, PairLike<int>&>);
|
||||
static_assert(constructible_from<pair<int&, int&>, PairLike<int>&>);
|
||||
static_assert(constructible_from<pair<const int&, const int&>, PairLike<int>&>);
|
||||
static_assert(!constructible_from<pair<int&&, int&&>, PairLike<int>&>);
|
||||
static_assert(!constructible_from<pair<const int&&, const int&&>, PairLike<int>&>);
|
||||
|
||||
// Test pair(pair-like) constructor with const PairLike<int>&
|
||||
static_assert(constructible_from<pair<int, int>, const PairLike<int>&>);
|
||||
static_assert(!constructible_from<pair<int&, int&>, const PairLike<int>&>);
|
||||
static_assert(constructible_from<pair<const int&, const int&>, const PairLike<int>&>);
|
||||
static_assert(!constructible_from<pair<int&&, int&&>, const PairLike<int>&>);
|
||||
static_assert(!constructible_from<pair<const int&&, const int&&>, const PairLike<int>&>);
|
||||
|
||||
// Test pair(pair-like) constructor with PairLike<int>
|
||||
static_assert(constructible_from<pair<int, int>, PairLike<int>>);
|
||||
static_assert(!constructible_from<pair<int&, int&>, PairLike<int>>);
|
||||
static_assert(constructible_from<pair<const int&, const int&>, PairLike<int>>);
|
||||
static_assert(constructible_from<pair<int&&, int&&>, PairLike<int>>);
|
||||
static_assert(constructible_from<pair<const int&&, const int&&>, PairLike<int>>);
|
||||
|
||||
// Test pair(pair-like) constructor with const PairLike<int>
|
||||
static_assert(constructible_from<pair<int, int>, const PairLike<int>>);
|
||||
static_assert(!constructible_from<pair<int&, int&>, const PairLike<int>>);
|
||||
static_assert(constructible_from<pair<const int&, const int&>, const PairLike<int>>);
|
||||
static_assert(!constructible_from<pair<int&&, int&&>, const PairLike<int>>);
|
||||
static_assert(constructible_from<pair<const int&&, const int&&>, const PairLike<int>>);
|
||||
|
||||
PairLike<TmpInt> a = {1, 2};
|
||||
|
||||
pair<TmpInt, TmpInt> p1(a);
|
||||
assert(p1.first == 1 && p1.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
pair<TmpInt&, TmpInt&> p2(a);
|
||||
assert(&p2.first == &get<0>(a) && &p2.second == &get<1>(a));
|
||||
|
||||
pair<const TmpInt&, const TmpInt&> p3(a);
|
||||
assert(&p3.first == &get<0>(a) && &p3.second == &get<1>(a));
|
||||
|
||||
pair<TmpInt, TmpInt> p4(as_const(a));
|
||||
assert(p4.first == 1 && p4.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
pair<const TmpInt&, const TmpInt&> p5(as_const(a));
|
||||
assert(&p5.first == &get<0>(a) && &p5.second == &get<1>(a));
|
||||
|
||||
pair<TmpInt, TmpInt> p6(std::move(a));
|
||||
assert(p6.first == 1 && p6.second == 2 && get<0>(a) == -1 && get<1>(a) == -1);
|
||||
tie(get<0>(a), get<1>(a)) = std::move(p6);
|
||||
|
||||
pair<const TmpInt&, const TmpInt&> p7(std::move(a));
|
||||
assert(&p7.first == &get<0>(a) && &p7.second == &get<1>(a));
|
||||
|
||||
pair<TmpInt&&, TmpInt&&> p8(std::move(a));
|
||||
assert(&p8.first == &get<0>(a) && &p8.second == &get<1>(a));
|
||||
|
||||
pair<const TmpInt&&, const TmpInt&&> p9(std::move(a));
|
||||
assert(&p9.first == &get<0>(a) && &p9.second == &get<1>(a));
|
||||
|
||||
pair<TmpInt, TmpInt> p10(std::move(as_const(a)));
|
||||
assert(p10.first == 1 && p10.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
pair<const TmpInt&, const TmpInt&> p11(std::move(as_const(a)));
|
||||
assert(p11.first == 1 && p11.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
pair<const TmpInt&&, const TmpInt&&> p12(std::move(as_const(a)));
|
||||
assert(p12.first == 1 && p12.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <template <class> class PairLike>
|
||||
constexpr bool test_pair_like_assignment() {
|
||||
static_assert(is_assignable_v<pair<int, int>&, PairLike<int>&>);
|
||||
static_assert(is_assignable_v<pair<int, int>&, const PairLike<int>&>);
|
||||
static_assert(is_assignable_v<pair<int, int>&, PairLike<int>>);
|
||||
static_assert(is_assignable_v<pair<int, int>&, const PairLike<int>>);
|
||||
|
||||
PairLike<TmpInt> a = {1, 2};
|
||||
|
||||
pair<TmpInt, TmpInt> p1;
|
||||
p1 = a;
|
||||
assert(p1.first == 1 && p1.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
pair<TmpInt, TmpInt> p2;
|
||||
p2 = as_const(a);
|
||||
assert(p2.first == 1 && p2.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
pair<TmpInt, TmpInt> p3;
|
||||
p3 = std::move(a);
|
||||
assert(p3.first == 1 && p3.second == 2 && get<0>(a) == -1 && get<1>(a) == -1);
|
||||
tie(get<0>(a), get<1>(a)) = std::move(p3);
|
||||
|
||||
pair<TmpInt, TmpInt> p4;
|
||||
p4 = std::move(as_const(a));
|
||||
assert(p4.first == 1 && p4.second == 2 && get<0>(a) == 1 && get<1>(a) == 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <template <class> class PairLike>
|
||||
constexpr bool test_pair_like_const_assignment() {
|
||||
using Ref = vector<bool>::reference;
|
||||
using Pair = pair<Ref, Ref>;
|
||||
|
||||
static_assert(is_assignable_v<const Pair&, PairLike<bool>&>);
|
||||
static_assert(is_assignable_v<const Pair&, const PairLike<bool>&>);
|
||||
static_assert(is_assignable_v<const Pair&, PairLike<bool>>);
|
||||
static_assert(is_assignable_v<const Pair&, const PairLike<bool>>);
|
||||
|
||||
vector<bool> bools = {false, true};
|
||||
PairLike<bool> a = {true, false};
|
||||
|
||||
const Pair p1{bools[0], bools[1]};
|
||||
p1 = a;
|
||||
assert(p1.first == true && p1.second == false);
|
||||
bools = {false, true};
|
||||
|
||||
const Pair p2{bools[0], bools[1]};
|
||||
p2 = as_const(a);
|
||||
assert(p2.first == true && p2.second == false);
|
||||
bools = {false, true};
|
||||
|
||||
const Pair p3{bools[0], bools[1]};
|
||||
p3 = std::move(a);
|
||||
assert(p3.first == true && p3.second == false);
|
||||
bools = {false, true};
|
||||
|
||||
const Pair p4{bools[0], bools[1]};
|
||||
p4 = std::move(as_const(a));
|
||||
assert(p4.first == true && p4.second == false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using BinaryTuple = tuple<T, T>;
|
||||
|
||||
template <class T>
|
||||
using BinaryArray = array<T, 2>;
|
||||
|
||||
int main() {
|
||||
static_assert(test_pair_like_constructor<BinaryArray>());
|
||||
assert((test_pair_like_constructor<BinaryArray>()));
|
||||
static_assert(test_pair_like_constructor<BinaryTuple>());
|
||||
assert((test_pair_like_constructor<BinaryTuple>()));
|
||||
|
||||
static_assert(test_pair_like_assignment<BinaryArray>());
|
||||
assert((test_pair_like_assignment<BinaryArray>()));
|
||||
static_assert(test_pair_like_assignment<BinaryTuple>());
|
||||
assert((test_pair_like_assignment<BinaryTuple>()));
|
||||
|
||||
static_assert(test_pair_like_const_assignment<BinaryArray>());
|
||||
assert((test_pair_like_const_assignment<BinaryArray>()));
|
||||
static_assert(test_pair_like_const_assignment<BinaryTuple>());
|
||||
assert((test_pair_like_const_assignment<BinaryTuple>()));
|
||||
}
|
Загрузка…
Ссылка в новой задаче