xref: /llvm-project/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp (revision dfde6e89ecc10b1f1eebdb0e409ef1a084030a6c)
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 #include <vector>
23 
24 #include "test_macros.h"
25 #include "variant_test_helpers.h"
26 
27 struct Dummy {
28   Dummy() = default;
29 };
30 
31 struct ThrowsT {
ThrowsTThrowsT32   ThrowsT(int) noexcept(false) {}
33 };
34 
35 struct NoThrowT {
NoThrowTNoThrowT36   NoThrowT(int) noexcept(true) {}
37 };
38 
39 struct AnyConstructible {
40   template <typename T>
AnyConstructibleAnyConstructible41   AnyConstructible(T&&) {}
42 };
43 struct NoConstructible {
44   NoConstructible() = delete;
45 };
46 template <class T>
47 struct RValueConvertibleFrom {
RValueConvertibleFromRValueConvertibleFrom48   RValueConvertibleFrom(T&&) {}
49 };
50 
test_T_ctor_noexcept()51 void test_T_ctor_noexcept() {
52   {
53     using V = std::variant<Dummy, NoThrowT>;
54     static_assert(std::is_nothrow_constructible<V, int>::value, "");
55   }
56   {
57     using V = std::variant<Dummy, ThrowsT>;
58     static_assert(!std::is_nothrow_constructible<V, int>::value, "");
59   }
60 }
61 
test_T_ctor_sfinae()62 void test_T_ctor_sfinae() {
63   {
64     using V = std::variant<long, long long>;
65     static_assert(!std::is_constructible<V, int>::value, "ambiguous");
66   }
67   {
68     using V = std::variant<std::string, std::string>;
69     static_assert(!std::is_constructible<V, const char*>::value, "ambiguous");
70   }
71   {
72     using V = std::variant<std::string, void*>;
73     static_assert(!std::is_constructible<V, int>::value, "no matching constructor");
74   }
75   {
76     using V = std::variant<std::string, float>;
77     static_assert(!std::is_constructible<V, int>::value, "no matching constructor");
78   }
79   {
80     using V = std::variant<std::unique_ptr<int>, bool>;
81     static_assert(!std::is_constructible<V, std::unique_ptr<char>>::value, "no explicit bool in constructor");
82     struct X {
83       operator void*();
84     };
85     static_assert(!std::is_constructible<V, X>::value, "no boolean conversion in constructor");
86     static_assert(std::is_constructible<V, std::false_type>::value, "converted to bool in constructor");
87   }
88   {
89     struct X {};
90     struct Y {
91       operator X();
92     };
93     using V = std::variant<X>;
94     static_assert(std::is_constructible<V, Y>::value, "regression on user-defined conversions in constructor");
95   }
96   {
97     using V = std::variant<AnyConstructible, NoConstructible>;
98     static_assert(!std::is_constructible<V, std::in_place_type_t<NoConstructible>>::value, "no matching constructor");
99     static_assert(!std::is_constructible<V, std::in_place_index_t<1>>::value, "no matching constructor");
100   }
101 }
102 
test_T_ctor_basic()103 void test_T_ctor_basic() {
104   {
105     constexpr std::variant<int> v(42);
106     static_assert(v.index() == 0, "");
107     static_assert(std::get<0>(v) == 42, "");
108   }
109   {
110     constexpr std::variant<int, long> v(42l);
111     static_assert(v.index() == 1, "");
112     static_assert(std::get<1>(v) == 42, "");
113   }
114   {
115     constexpr std::variant<unsigned, long> v(42);
116     static_assert(v.index() == 1, "");
117     static_assert(std::get<1>(v) == 42, "");
118   }
119   {
120     std::variant<std::string, bool const> v = "foo";
121     assert(v.index() == 0);
122     assert(std::get<0>(v) == "foo");
123   }
124   {
125     std::variant<bool, std::unique_ptr<int>> v = nullptr;
126     assert(v.index() == 1);
127     assert(std::get<1>(v) == nullptr);
128   }
129   {
130     std::variant<bool const, int> v = true;
131     assert(v.index() == 0);
132     assert(std::get<0>(v));
133   }
134   {
135     std::variant<RValueConvertibleFrom<int>> v1 = 42;
136     assert(v1.index() == 0);
137 
138     int x                                                         = 42;
139     std::variant<RValueConvertibleFrom<int>, AnyConstructible> v2 = x;
140     assert(v2.index() == 1);
141   }
142 }
143 
144 struct BoomOnAnything {
145   template <class T>
BoomOnAnythingBoomOnAnything146   constexpr BoomOnAnything(T) {
147     static_assert(!std::is_same<T, T>::value, "");
148   }
149 };
150 
test_no_narrowing_check_for_class_types()151 void test_no_narrowing_check_for_class_types() {
152   using V = std::variant<int, BoomOnAnything>;
153   V v(42);
154   assert(v.index() == 0);
155   assert(std::get<0>(v) == 42);
156 }
157 
158 struct Bar {};
159 struct Baz {};
test_construction_with_repeated_types()160 void test_construction_with_repeated_types() {
161   using V = std::variant<int, Bar, Baz, int, Baz, int, int>;
162   static_assert(!std::is_constructible<V, int>::value, "");
163   static_assert(!std::is_constructible<V, Baz>::value, "");
164   // OK, the selected type appears only once and so it shouldn't
165   // be affected by the duplicate types.
166   static_assert(std::is_constructible<V, Bar>::value, "");
167 }
168 
test_vector_bool()169 void test_vector_bool() {
170   std::vector<bool> vec = {true};
171   std::variant<bool, int> v = vec[0];
172   assert(v.index() == 0);
173   assert(std::get<0>(v) == true);
174 }
175 
main(int,char **)176 int main(int, char**) {
177   test_T_ctor_basic();
178   test_T_ctor_noexcept();
179   test_T_ctor_sfinae();
180   test_no_narrowing_check_for_class_types();
181   test_construction_with_repeated_types();
182   test_vector_bool();
183   return 0;
184 }
185