150 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 11// <utility>12 13// template <class T1, class T2> struct pair14 15// template <pair-like P>16// constexpr explicit(see-below) pair(P&&); // since C++2317 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_ns39 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://llvm.org/PR6562049// This used to be a hard error50static_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::subrange55 {56 // Check from std::array57 {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 small63 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 large65 }66 67 // Check from std::tuple68 {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 small74 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 large76 }77 78 // Check that the constructor excludes ranges::subrange79 {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's83 // constructor does not exclude subrange84 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-like91 {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 convertible97 static_assert(!std::is_constructible_v<std::pair<long, std::string>, std::tuple<long, void*>>); // second not convertible98 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 elements102 {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 converted114 {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 explicit123 {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 explicit130 {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