1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10
11// <utility>
12
13// template <class T1, class T2> struct pair
14
15// template <pair-like P>
16// constexpr explicit(see-below) pair(P&&); // since C++23
17
18#include <array>
19#include <cassert>
20#include <ranges>
21#include <string>
22#include <tuple>
23#include <type_traits>
24#include <utility>
25
26namespace my_ns{
27
28struct MyPairLike {
29
30template <std::size_t N>
31friend int get(MyPairLike const&)
32{
33 return 0;
34}
35
36};
37
38} // namespace my_ns
39
40namespace std {
41
42template <>
43struct tuple_size<my_ns::MyPairLike> : std::integral_constant<std::size_t, 2> {};
44
45template <std::size_t N>
46struct tuple_element<N, my_ns::MyPairLike> {
47 using type = int;
48};
49
50} // namespace std
51
52// https://github.com/llvm/llvm-project/issues/65620
53// This used to be a hard error
54static_assert(!std::is_constructible_v<std::pair<int,int>, my_ns::MyPairLike const&>);
55
56
57constexpr bool test() {
58 // Make sure construction works from array, tuple, and ranges::subrange
59 {
60 // Check from std::array
61 {
62 std::array<int, 2> a = {1, 2};
63 std::pair<int, int> p(a);
64 assert(p.first == 1);
65 assert(p.second == 2);
66 static_assert(!std::is_constructible_v<std::pair<int, int>, std::array<int, 1>>); // too small
67 static_assert( std::is_constructible_v<std::pair<int, int>, std::array<int, 2>>); // works (test the test)
68 static_assert(!std::is_constructible_v<std::pair<int, int>, std::array<int, 3>>); // too large
69 }
70
71 // Check from std::tuple
72 {
73 std::tuple<int, int> a = {1, 2};
74 std::pair<int, int> p(a);
75 assert(p.first == 1);
76 assert(p.second == 2);
77 static_assert(!std::is_constructible_v<std::pair<int, int>, std::tuple<int>>); // too small
78 static_assert( std::is_constructible_v<std::pair<int, int>, std::tuple<int, int>>); // works (test the test)
79 static_assert(!std::is_constructible_v<std::pair<int, int>, std::tuple<int, int, int>>); // too large
80 }
81
82 // Check that the constructor excludes ranges::subrange
83 {
84 int data[] = {1, 2, 3, 4, 5};
85 const std::ranges::subrange a(data);
86 // Note the expression below would be ambiguous if pair's
87 // constructor does not exclude subrange
88 std::pair<int*, int*> p = a;
89 assert(p.first == data + 0);
90 assert(p.second == data + 5);
91 }
92 }
93
94 // Make sure we allow element conversion from a pair-like
95 {
96 std::tuple<int, char const*> a = {34, "hello world"};
97 std::pair<long, std::string> p(a);
98 assert(p.first == 34);
99 assert(p.second == std::string("hello world"));
100 static_assert(!std::is_constructible_v<std::pair<long, std::string>, std::tuple<char*, std::string>>); // first not convertible
101 static_assert(!std::is_constructible_v<std::pair<long, std::string>, std::tuple<long, void*>>); // second not convertible
102 static_assert( std::is_constructible_v<std::pair<long, std::string>, std::tuple<long, std::string>>); // works (test the test)
103 }
104
105 // Make sure we forward the pair-like elements
106 {
107 struct NoCopy {
108 NoCopy() = default;
109 NoCopy(NoCopy const&) = delete;
110 NoCopy(NoCopy&&) = default;
111 };
112 std::tuple<NoCopy, NoCopy> a;
113 std::pair<NoCopy, NoCopy> p(std::move(a));
114 (void)p;
115 }
116
117 // Make sure the constructor is implicit iff both elements can be converted
118 {
119 struct To { };
120 struct FromImplicit {
121 constexpr operator To() const { return To{}; }
122 };
123 struct FromExplicit {
124 constexpr explicit operator To() const { return To{}; }
125 };
126 // If both are convertible, the constructor is not explicit
127 {
128 std::tuple<FromImplicit, float> a = {FromImplicit{}, 2.3f};
129 std::pair<To, double> p = a;
130 (void)p;
131 static_assert(std::is_convertible_v<std::tuple<FromImplicit, float>, std::pair<To, double>>);
132 }
133 // Otherwise, the constructor is explicit
134 {
135 static_assert( std::is_constructible_v<std::pair<To, int>, std::tuple<FromExplicit, int>>);
136 static_assert(!std::is_convertible_v<std::tuple<FromExplicit, int>, std::pair<To, int>>);
137
138 static_assert( std::is_constructible_v<std::pair<int, To>, std::tuple<int, FromExplicit>>);
139 static_assert(!std::is_convertible_v<std::tuple<int, FromExplicit>, std::pair<int, To>>);
140
141 static_assert( std::is_constructible_v<std::pair<To, To>, std::tuple<FromExplicit, FromExplicit>>);
142 static_assert(!std::is_convertible_v<std::tuple<FromExplicit, FromExplicit>, std::pair<To, To>>);
143 }
144 }
145 return true;
146}
147
148int main(int, char**) {
149 test();
150 static_assert(test());
151
152 return 0;
153}
154

source code of libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.pair_like.pass.cpp