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

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