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, c++17, c++20 10 11 // template<class U, class... Args> 12 // constexpr T& emplace(initializer_list<U> il, Args&&... args) noexcept; 13 // Constraints: is_nothrow_constructible_v<T, initializer_list<U>&, Args...> is true. 14 // 15 // Effects: Equivalent to: 16 // if (has_value()) { 17 // destroy_at(addressof(val)); 18 // } else { 19 // destroy_at(addressof(unex)); 20 // has_val = true; 21 // } 22 // return *construct_at(addressof(val), il, std::forward<Args>(args)...); 23 24 #include <algorithm> 25 #include <cassert> 26 #include <concepts> 27 #include <expected> 28 #include <type_traits> 29 #include <utility> 30 31 #include "../../types.h" 32 #include "test_macros.h" 33 34 template <class T, class... Args> 35 concept CanEmplace = requires(T t, Args&&... args) { t.emplace(std::forward<Args>(args)...); }; 36 37 static_assert(CanEmplace<std::expected<int, int>, int>); 38 39 template <bool Noexcept> 40 struct CtorFromInitializerList { 41 CtorFromInitializerList(std::initializer_list<int>&) noexcept(Noexcept); 42 CtorFromInitializerList(std::initializer_list<int>&, int) noexcept(Noexcept); 43 }; 44 45 static_assert(CanEmplace<std::expected<CtorFromInitializerList<true>, int>, std::initializer_list<int>&>); 46 static_assert(!CanEmplace<std::expected<CtorFromInitializerList<false>, int>, std::initializer_list<int>&>); 47 static_assert(CanEmplace<std::expected<CtorFromInitializerList<true>, int>, std::initializer_list<int>&, int>); 48 static_assert(!CanEmplace<std::expected<CtorFromInitializerList<false>, int>, std::initializer_list<int>&, int>); 49 50 struct Data { 51 std::initializer_list<int> il; 52 int i; 53 54 constexpr Data(std::initializer_list<int>& l, int ii) noexcept : il(l), i(ii) {} 55 }; 56 57 constexpr bool test() { 58 // has_value 59 { 60 auto list1 = {1, 2, 3}; 61 auto list2 = {4, 5, 6}; 62 std::expected<Data, int> e(std::in_place, list1, 5); 63 decltype(auto) x = e.emplace(list2, 10); 64 static_assert(std::same_as<decltype(x), Data&>); 65 assert(&x == &(*e)); 66 67 assert(e.has_value()); 68 assert(std::ranges::equal(e.value().il, list2)); 69 assert(e.value().i == 10); 70 } 71 72 // !has_value 73 { 74 auto list = {4, 5, 6}; 75 std::expected<Data, int> e(std::unexpect, 5); 76 decltype(auto) x = e.emplace(list, 10); 77 static_assert(std::same_as<decltype(x), Data&>); 78 assert(&x == &(*e)); 79 80 assert(e.has_value()); 81 assert(std::ranges::equal(e.value().il, list)); 82 assert(e.value().i == 10); 83 } 84 85 // TailClobberer 86 { 87 std::expected<TailClobberer<0>, bool> e(std::unexpect); 88 auto list = {4, 5, 6}; 89 e.emplace(list); 90 assert(e.has_value()); 91 } 92 93 return true; 94 } 95 96 int main(int, char**) { 97 test(); 98 static_assert(test()); 99 return 0; 100 } 101