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 // <tuple> 10 11 // template <class... Types> 12 // template <class... UTypes> 13 // constexpr explicit(see below) tuple<Types>::tuple(const 14 // tuple<UTypes...>&&); 15 // 16 // Constraints: 17 // sizeof...(Types) equals sizeof...(UTypes) && 18 // (is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...) is true && 19 // ( 20 // sizeof...(Types) is not 1 || 21 // ( 22 // !is_convertible_v<decltype(u), T> && 23 // !is_constructible_v<T, decltype(u)> && 24 // !is_same_v<T, U> 25 // ) 26 // ) 27 28 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 29 30 #include <cassert> 31 #include <tuple> 32 33 #include "convert_types.h" 34 #include "test_macros.h" 35 36 // test: The expression inside explicit is equivalent to: 37 // !(is_convertible_v<decltype(get<I>(FWD(u))), Types> && ...) 38 static_assert(std::is_convertible_v<const std::tuple<ConstMove>&&, std::tuple<ConvertibleFrom<ConstMove>>>); 39 40 static_assert(std::is_convertible_v<const std::tuple<ConstMove, ConstMove>&&, 41 std::tuple<ConvertibleFrom<ConstMove>, ConvertibleFrom<ConstMove>>>); 42 43 static_assert( 44 !std::is_convertible_v<const std::tuple<MutableCopy>&&, std::tuple<ExplicitConstructibleFrom<ConstMove>>>); 45 46 static_assert(!std::is_convertible_v<const std::tuple<ConstMove, ConstMove>&&, 47 std::tuple<ConvertibleFrom<ConstMove>, ExplicitConstructibleFrom<ConstMove>>>); 48 49 constexpr bool test() { 50 // test implicit conversions. 51 // sizeof...(Types) == 1 52 { 53 const std::tuple<ConstMove> t1{1}; 54 std::tuple<ConvertibleFrom<ConstMove>> t2 = std::move(t1); 55 assert(std::get<0>(t2).v.val == 1); 56 } 57 58 // test implicit conversions. 59 // sizeof...(Types) > 1 60 { 61 const std::tuple<ConstMove, int> t1{1, 2}; 62 std::tuple<ConvertibleFrom<ConstMove>, int> t2 = std::move(t1); 63 assert(std::get<0>(t2).v.val == 1); 64 assert(std::get<1>(t2) == 2); 65 } 66 67 // test explicit conversions. 68 // sizeof...(Types) == 1 69 { 70 const std::tuple<ConstMove> t1{1}; 71 std::tuple<ExplicitConstructibleFrom<ConstMove>> t2{std::move(t1)}; 72 assert(std::get<0>(t2).v.val == 1); 73 } 74 75 // test explicit conversions. 76 // sizeof...(Types) > 1 77 { 78 const std::tuple<ConstMove, int> t1{1, 2}; 79 std::tuple<ExplicitConstructibleFrom<ConstMove>, int> t2{std::move(t1)}; 80 assert(std::get<0>(t2).v.val == 1); 81 assert(std::get<1>(t2) == 2); 82 } 83 84 // test constraints 85 86 // sizeof...(Types) != sizeof...(UTypes) 87 static_assert(!std::is_constructible_v<std::tuple<int, int>, const std::tuple<int>&&>); 88 static_assert(!std::is_constructible_v<std::tuple<int, int, int>, const std::tuple<int, int>&&>); 89 90 // !(is_constructible_v<Types, decltype(get<I>(FWD(u)))> && ...) 91 static_assert(!std::is_constructible_v<std::tuple<int, NoConstructorFromInt>, const std::tuple<int, int>&&>); 92 93 // sizeof...(Types) == 1 && other branch of "||" satisfied 94 { 95 const std::tuple<TracedCopyMove> t1{}; 96 std::tuple<ConvertibleFrom<TracedCopyMove>> t2{std::move(t1)}; 97 assert(constMoveCtrCalled(std::get<0>(t2).v)); 98 } 99 100 // sizeof...(Types) == 1 && is_same_v<T, U> 101 { 102 const std::tuple<TracedCopyMove> t1{}; 103 std::tuple<TracedCopyMove> t2{t1}; 104 assert(!constMoveCtrCalled(std::get<0>(t2))); 105 } 106 107 // sizeof...(Types) != 1 108 { 109 const std::tuple<TracedCopyMove, TracedCopyMove> t1{}; 110 std::tuple<TracedCopyMove, TracedCopyMove> t2{std::move(t1)}; 111 assert(constMoveCtrCalled(std::get<0>(t2))); 112 } 113 114 // These two test points cause gcc to ICE 115 #if !defined(TEST_COMPILER_GCC) 116 // sizeof...(Types) == 1 && is_convertible_v<decltype(u), T> 117 { 118 const std::tuple<CvtFromConstTupleRefRef> t1{}; 119 std::tuple<ConvertibleFrom<CvtFromConstTupleRefRef>> t2{std::move(t1)}; 120 assert(!constMoveCtrCalled(std::get<0>(t2).v)); 121 } 122 123 // sizeof...(Types) == 1 && is_constructible_v<decltype(u), T> 124 { 125 const std::tuple<ExplicitCtrFromConstTupleRefRef> t1{}; 126 std::tuple<ConvertibleFrom<ExplicitCtrFromConstTupleRefRef>> t2{std::move(t1)}; 127 assert(!constMoveCtrCalled(std::get<0>(t2).v)); 128 } 129 #endif 130 131 return true; 132 } 133 134 int main(int, char**) { 135 test(); 136 static_assert(test()); 137 return 0; 138 } 139