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