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
40template <>
41struct std::tuple_size<my_ns::MyPairLike> : std::integral_constant<std::size_t, 2> {};
42
43template <std::size_t N>
44struct std::tuple_element<N, my_ns::MyPairLike> {
45 using type = int;
46};
47
48// https://github.com/llvm/llvm-project/issues/65620
49// This used to be a hard error
50static_assert(!std::is_constructible_v<std::pair<int,int>, my_ns::MyPairLike const&>);
51
52
53constexpr bool test() {
54 // Make sure construction works from array, tuple, and ranges::subrange
55 {
56 // Check from std::array
57 {
58 std::array<int, 2> a = {1, 2};
59 std::pair<int, int> p(a);
60 assert(p.first == 1);
61 assert(p.second == 2);
62 static_assert(!std::is_constructible_v<std::pair<int, int>, std::array<int, 1>>); // too small
63 static_assert( std::is_constructible_v<std::pair<int, int>, std::array<int, 2>>); // works (test the test)
64 static_assert(!std::is_constructible_v<std::pair<int, int>, std::array<int, 3>>); // too large
65 }
66
67 // Check from std::tuple
68 {
69 std::tuple<int, int> a = {1, 2};
70 std::pair<int, int> p(a);
71 assert(p.first == 1);
72 assert(p.second == 2);
73 static_assert(!std::is_constructible_v<std::pair<int, int>, std::tuple<int>>); // too small
74 static_assert( std::is_constructible_v<std::pair<int, int>, std::tuple<int, int>>); // works (test the test)
75 static_assert(!std::is_constructible_v<std::pair<int, int>, std::tuple<int, int, int>>); // too large
76 }
77
78 // Check that the constructor excludes ranges::subrange
79 {
80 int data[] = {1, 2, 3, 4, 5};
81 const std::ranges::subrange a(data);
82 // Note the expression below would be ambiguous if pair's
83 // constructor does not exclude subrange
84 std::pair<int*, int*> p = a;
85 assert(p.first == data + 0);
86 assert(p.second == data + 5);
87 }
88 }
89
90 // Make sure we allow element conversion from a pair-like
91 {
92 std::tuple<int, char const*> a = {34, "hello world"};
93 std::pair<long, std::string> p(a);
94 assert(p.first == 34);
95 assert(p.second == std::string("hello world"));
96 static_assert(!std::is_constructible_v<std::pair<long, std::string>, std::tuple<char*, std::string>>); // first not convertible
97 static_assert(!std::is_constructible_v<std::pair<long, std::string>, std::tuple<long, void*>>); // second not convertible
98 static_assert( std::is_constructible_v<std::pair<long, std::string>, std::tuple<long, std::string>>); // works (test the test)
99 }
100
101 // Make sure we forward the pair-like elements
102 {
103 struct NoCopy {
104 NoCopy() = default;
105 NoCopy(NoCopy const&) = delete;
106 NoCopy(NoCopy&&) = default;
107 };
108 std::tuple<NoCopy, NoCopy> a;
109 std::pair<NoCopy, NoCopy> p(std::move(a));
110 (void)p;
111 }
112
113 // Make sure the constructor is implicit iff both elements can be converted
114 {
115 struct To { };
116 struct FromImplicit {
117 constexpr operator To() const { return To{}; }
118 };
119 struct FromExplicit {
120 constexpr explicit operator To() const { return To{}; }
121 };
122 // If both are convertible, the constructor is not explicit
123 {
124 std::tuple<FromImplicit, float> a = {FromImplicit{}, 2.3f};
125 std::pair<To, double> p = a;
126 (void)p;
127 static_assert(std::is_convertible_v<std::tuple<FromImplicit, float>, std::pair<To, double>>);
128 }
129 // Otherwise, the constructor is explicit
130 {
131 static_assert( std::is_constructible_v<std::pair<To, int>, std::tuple<FromExplicit, int>>);
132 static_assert(!std::is_convertible_v<std::tuple<FromExplicit, int>, std::pair<To, int>>);
133
134 static_assert( std::is_constructible_v<std::pair<int, To>, std::tuple<int, FromExplicit>>);
135 static_assert(!std::is_convertible_v<std::tuple<int, FromExplicit>, std::pair<int, To>>);
136
137 static_assert( std::is_constructible_v<std::pair<To, To>, std::tuple<FromExplicit, FromExplicit>>);
138 static_assert(!std::is_convertible_v<std::tuple<FromExplicit, FromExplicit>, std::pair<To, To>>);
139 }
140 }
141 return true;
142}
143
144int main(int, char**) {
145 test();
146 static_assert(test());
147
148 return 0;
149}
150

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