1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++98, c++03, c++11, c++14
11 
12 // XFAIL: dylib-has-no-bad_variant_access && !libcpp-no-exceptions
13 
14 // <variant>
15 
16 // template <class ...Types> class variant;
17 
18 // template <size_t I, class ...Args>
19 //   variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);
20 
21 #include <cassert>
22 #include <string>
23 #include <type_traits>
24 #include <variant>
25 
26 #include "archetypes.h"
27 #include "test_convertible.h"
28 #include "test_macros.h"
29 #include "variant_test_helpers.h"
30 
31 template <class Var, size_t I, class... Args>
32 constexpr auto test_emplace_exists_imp(int) -> decltype(
33     std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
34   return true;
35 }
36 
37 template <class, size_t, class...>
38 constexpr auto test_emplace_exists_imp(long) -> bool {
39   return false;
40 }
41 
42 template <class Var, size_t I, class... Args> constexpr bool emplace_exists() {
43   return test_emplace_exists_imp<Var, I, Args...>(0);
44 }
45 
46 void test_emplace_sfinae() {
47   {
48     using V = std::variant<int, void *, const void *, TestTypes::NoCtors>;
49     static_assert(emplace_exists<V, 0>(), "");
50     static_assert(emplace_exists<V, 0, int>(), "");
51     static_assert(!emplace_exists<V, 0, decltype(nullptr)>(),
52                   "cannot construct");
53     static_assert(emplace_exists<V, 1, decltype(nullptr)>(), "");
54     static_assert(emplace_exists<V, 1, int *>(), "");
55     static_assert(!emplace_exists<V, 1, const int *>(), "");
56     static_assert(!emplace_exists<V, 1, int>(), "cannot construct");
57     static_assert(emplace_exists<V, 2, const int *>(), "");
58     static_assert(emplace_exists<V, 2, int *>(), "");
59     static_assert(!emplace_exists<V, 3>(), "cannot construct");
60   }
61 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
62   {
63     using V = std::variant<int, int &, const int &, int &&, TestTypes::NoCtors>;
64     static_assert(emplace_exists<V, 0>(), "");
65     static_assert(emplace_exists<V, 0, int>(), "");
66     static_assert(emplace_exists<V, 0, long long>(), "");
67     static_assert(!emplace_exists<V, 0, int, int>(), "too many args");
68     static_assert(emplace_exists<V, 1, int &>(), "");
69     static_assert(!emplace_exists<V, 1>(), "cannot default construct ref");
70     static_assert(!emplace_exists<V, 1, const int &>(), "cannot bind ref");
71     static_assert(!emplace_exists<V, 1, int &&>(), "cannot bind ref");
72     static_assert(emplace_exists<V, 2, int &>(), "");
73     static_assert(emplace_exists<V, 2, const int &>(), "");
74     static_assert(emplace_exists<V, 2, int &&>(), "");
75     static_assert(!emplace_exists<V, 2, void *>(),
76                   "not constructible from void*");
77     static_assert(emplace_exists<V, 3, int>(), "");
78     static_assert(!emplace_exists<V, 3, int &>(), "cannot bind ref");
79     static_assert(!emplace_exists<V, 3, const int &>(), "cannot bind ref");
80     static_assert(!emplace_exists<V, 3, const int &&>(), "cannot bind ref");
81     static_assert(!emplace_exists<V, 4>(), "no ctors");
82   }
83 #endif
84 }
85 
86 void test_basic() {
87   {
88     using V = std::variant<int>;
89     V v(42);
90     auto& ref1 = v.emplace<0>();
91     static_assert(std::is_same_v<int&, decltype(ref1)>, "");
92     assert(std::get<0>(v) == 0);
93     assert(&ref1 == &std::get<0>(v));
94     auto& ref2 = v.emplace<0>(42);
95     static_assert(std::is_same_v<int&, decltype(ref2)>, "");
96     assert(std::get<0>(v) == 42);
97     assert(&ref2 == &std::get<0>(v));
98   }
99   {
100     using V =
101         std::variant<int, long, const void *, TestTypes::NoCtors, std::string>;
102     const int x = 100;
103     V v(std::in_place_index<0>, -1);
104     // default emplace a value
105     auto& ref1 = v.emplace<1>();
106     static_assert(std::is_same_v<long&, decltype(ref1)>, "");
107     assert(std::get<1>(v) == 0);
108     assert(&ref1 == &std::get<1>(v));
109     auto& ref2 = v.emplace<2>(&x);
110     static_assert(std::is_same_v<const void*&, decltype(ref2)>, "");
111     assert(std::get<2>(v) == &x);
112     assert(&ref2 == &std::get<2>(v));
113     // emplace with multiple args
114     auto& ref3 = v.emplace<4>(3u, 'a');
115     static_assert(std::is_same_v<std::string&, decltype(ref3)>, "");
116     assert(std::get<4>(v) == "aaa");
117     assert(&ref3 == &std::get<4>(v));
118   }
119 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
120   {
121     using V = std::variant<int, long, const int &, int &&, TestTypes::NoCtors,
122                            std::string>;
123     const int x = 100;
124     int y = 42;
125     int z = 43;
126     V v(std::in_place_index<0>, -1);
127     // default emplace a value
128     auto& ref1 = v.emplace<1>();
129     static_assert(std::is_same_v<long&, decltype(ref1)>, "");
130     assert(std::get<1>(v) == 0);
131     assert(&ref1 == &std::get<1>(v));
132     // emplace a reference
133     auto& ref2 = v.emplace<2>(x);
134     static_assert(std::is_same_v<&, decltype(ref)>, "");
135     assert(&std::get<2>(v) == &x);
136     assert(&ref2 == &std::get<2>(v));
137     // emplace an rvalue reference
138     auto& ref3 = v.emplace<3>(std::move(y));
139     static_assert(std::is_same_v<&, decltype(ref)>, "");
140     assert(&std::get<3>(v) == &y);
141     assert(&ref3 == &std::get<3>(v));
142     // re-emplace a new reference over the active member
143     auto& ref4 = v.emplace<3>(std::move(z));
144     static_assert(std::is_same_v<&, decltype(ref)>, "");
145     assert(&std::get<3>(v) == &z);
146     assert(&ref4 == &std::get<3>(v));
147     // emplace with multiple args
148     auto& ref5 = v.emplace<5>(3u, 'a');
149     static_assert(std::is_same_v<std::string&, decltype(ref5)>, "");
150     assert(std::get<5>(v) == "aaa");
151     assert(&ref5 == &std::get<5>(v));
152   }
153 #endif
154 }
155 
156 int main(int, char**) {
157   test_basic();
158   test_emplace_sfinae();
159 
160   return 0;
161 }
162