xref: /llvm-project/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp (revision ec350ad418a24f70c88758259c774a1e11c06d74)
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 // UNSUPPORTED: c++03, c++11, c++14
10 
11 // <variant>
12 
13 // template <class ...Types> class variant;
14 
15 // template <class T> constexpr variant(T&&) noexcept(see below);
16 
17 #include <cassert>
18 #include <string>
19 #include <type_traits>
20 #include <variant>
21 #include <memory>
22 
23 #include "test_macros.h"
24 #include "variant_test_helpers.h"
25 
26 struct Dummy {
27   Dummy() = default;
28 };
29 
30 struct ThrowsT {
31   ThrowsT(int) noexcept(false) {}
32 };
33 
34 struct NoThrowT {
35   NoThrowT(int) noexcept(true) {}
36 };
37 
38 struct AnyConstructible { template <typename T> AnyConstructible(T&&) {} };
39 struct NoConstructible { NoConstructible() = delete; };
40 template <class T>
41 struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} };
42 
43 void test_T_ctor_noexcept() {
44   {
45     using V = std::variant<Dummy, NoThrowT>;
46     static_assert(std::is_nothrow_constructible<V, int>::value, "");
47   }
48   {
49     using V = std::variant<Dummy, ThrowsT>;
50     static_assert(!std::is_nothrow_constructible<V, int>::value, "");
51   }
52 }
53 
54 void test_T_ctor_sfinae() {
55   {
56     using V = std::variant<long, long long>;
57     static_assert(!std::is_constructible<V, int>::value, "ambiguous");
58   }
59   {
60     using V = std::variant<std::string, std::string>;
61     static_assert(!std::is_constructible<V, const char *>::value, "ambiguous");
62   }
63   {
64     using V = std::variant<std::string, void *>;
65     static_assert(!std::is_constructible<V, int>::value,
66                   "no matching constructor");
67   }
68   {
69     using V = std::variant<std::string, float>;
70     static_assert(std::is_constructible<V, int>::value == VariantAllowsNarrowingConversions,
71                   "no matching constructor");
72   }
73   {
74     using V = std::variant<std::unique_ptr<int>, bool>;
75     static_assert(!std::is_constructible<V, std::unique_ptr<char>>::value,
76                   "no explicit bool in constructor");
77     struct X {
78       operator void*();
79     };
80     static_assert(!std::is_constructible<V, X>::value,
81                   "no boolean conversion in constructor");
82     static_assert(!std::is_constructible<V, std::false_type>::value,
83                   "no converted to bool in constructor");
84   }
85   {
86     struct X {};
87     struct Y {
88       operator X();
89     };
90     using V = std::variant<X>;
91     static_assert(std::is_constructible<V, Y>::value,
92                   "regression on user-defined conversions in constructor");
93   }
94   {
95     using V = std::variant<AnyConstructible, NoConstructible>;
96     static_assert(
97         !std::is_constructible<V, std::in_place_type_t<NoConstructible>>::value,
98         "no matching constructor");
99     static_assert(!std::is_constructible<V, std::in_place_index_t<1>>::value,
100                   "no matching constructor");
101   }
102 
103 
104 
105 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
106   {
107     using V = std::variant<int, int &&>;
108     static_assert(!std::is_constructible<V, int>::value, "ambiguous");
109   }
110   {
111     using V = std::variant<int, const int &>;
112     static_assert(!std::is_constructible<V, int>::value, "ambiguous");
113   }
114 #endif
115 }
116 
117 void test_T_ctor_basic() {
118   {
119     constexpr std::variant<int> v(42);
120     static_assert(v.index() == 0, "");
121     static_assert(std::get<0>(v) == 42, "");
122   }
123   {
124     constexpr std::variant<int, long> v(42l);
125     static_assert(v.index() == 1, "");
126     static_assert(std::get<1>(v) == 42, "");
127   }
128 #ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
129   {
130     constexpr std::variant<unsigned, long> v(42);
131     static_assert(v.index() == 1, "");
132     static_assert(std::get<1>(v) == 42, "");
133   }
134 #endif
135   {
136     std::variant<std::string, bool const> v = "foo";
137     assert(v.index() == 0);
138     assert(std::get<0>(v) == "foo");
139   }
140   {
141     std::variant<bool volatile, std::unique_ptr<int>> v = nullptr;
142     assert(v.index() == 1);
143     assert(std::get<1>(v) == nullptr);
144   }
145   {
146     std::variant<bool volatile const, int> v = true;
147     assert(v.index() == 0);
148     assert(std::get<0>(v));
149   }
150   {
151     std::variant<RValueConvertibleFrom<int>> v1 = 42;
152     assert(v1.index() == 0);
153 
154     int x = 42;
155     std::variant<RValueConvertibleFrom<int>, AnyConstructible> v2 = x;
156     assert(v2.index() == 1);
157   }
158 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
159   {
160     using V = std::variant<const int &, int &&, long>;
161     static_assert(std::is_convertible<int &, V>::value, "must be implicit");
162     int x = 42;
163     V v(x);
164     assert(v.index() == 0);
165     assert(&std::get<0>(v) == &x);
166   }
167   {
168     using V = std::variant<const int &, int &&, long>;
169     static_assert(std::is_convertible<int, V>::value, "must be implicit");
170     int x = 42;
171     V v(std::move(x));
172     assert(v.index() == 1);
173     assert(&std::get<1>(v) == &x);
174   }
175 #endif
176 }
177 
178 struct BoomOnAnything {
179   template <class T>
180   constexpr BoomOnAnything(T) { static_assert(!std::is_same<T, T>::value, ""); }
181 };
182 
183 void test_no_narrowing_check_for_class_types() {
184   using V = std::variant<int, BoomOnAnything>;
185   V v(42);
186   assert(v.index() == 0);
187   assert(std::get<0>(v) == 42);
188 }
189 
190 struct Bar {};
191 struct Baz {};
192 void test_construction_with_repeated_types() {
193   using V = std::variant<int, Bar, Baz, int, Baz, int, int>;
194   static_assert(!std::is_constructible<V, int>::value, "");
195   static_assert(!std::is_constructible<V, Baz>::value, "");
196   // OK, the selected type appears only once and so it shouldn't
197   // be affected by the duplicate types.
198   static_assert(std::is_constructible<V, Bar>::value, "");
199 }
200 
201 int main(int, char**) {
202   test_T_ctor_basic();
203   test_T_ctor_noexcept();
204   test_T_ctor_sfinae();
205   test_no_narrowing_check_for_class_types();
206   test_construction_with_repeated_types();
207   return 0;
208 }
209