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 "copy_move_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> && ...)
38static_assert(std::is_convertible_v<const std::tuple<ConstMove>&&, std::tuple<ConvertibleFrom<ConstMove>>>);
39
40static_assert(std::is_convertible_v<const std::tuple<ConstMove, ConstMove>&&,
41 std::tuple<ConvertibleFrom<ConstMove>, ConvertibleFrom<ConstMove>>>);
42
43static_assert(
44 !std::is_convertible_v<const std::tuple<MutableCopy>&&, std::tuple<ExplicitConstructibleFrom<ConstMove>>>);
45
46static_assert(!std::is_convertible_v<const std::tuple<ConstMove, ConstMove>&&,
47 std::tuple<ConvertibleFrom<ConstMove>, ExplicitConstructibleFrom<ConstMove>>>);
48
49constexpr 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
134int main(int, char**) {
135 test();
136 static_assert(test());
137 return 0;
138}
139

source code of libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/convert_const_move.pass.cpp