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