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