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 10 // UNSUPPORTED: libcpp-no-concepts 11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 12 13 // <algorithm> 14 // 15 // namespace ranges { 16 // template<class InputIterator, class OutputIterator> 17 // struct in_out_result; 18 // } 19 20 #include <algorithm> 21 #include <cassert> 22 #include <type_traits> 23 24 struct A { 25 A(int&); 26 }; 27 static_assert(!std::is_constructible_v<std::ranges::in_out_result<A, A>, std::ranges::in_out_result<int, int>&>); 28 29 static_assert(std::is_convertible_v<std::ranges::in_out_result<int, int>&, 30 std::ranges::in_out_result<long, long>>); 31 static_assert(!std::is_nothrow_convertible_v<std::ranges::in_out_result<int, int>&, 32 std::ranges::in_out_result<long, long>>); 33 static_assert(std::is_convertible_v<const std::ranges::in_out_result<int, int>&, 34 std::ranges::in_out_result<long, long>>); 35 static_assert(!std::is_nothrow_convertible_v<const std::ranges::in_out_result<int, int>&, 36 std::ranges::in_out_result<long, long>>); 37 static_assert(std::is_convertible_v<std::ranges::in_out_result<int, int>&&, 38 std::ranges::in_out_result<long, long>>); 39 static_assert(!std::is_nothrow_convertible_v<std::ranges::in_out_result<int, int>&&, 40 std::ranges::in_out_result<long, long>>); 41 static_assert(std::is_convertible_v<const std::ranges::in_out_result<int, int>&&, 42 std::ranges::in_out_result<long, long>>); 43 static_assert(!std::is_nothrow_convertible_v<const std::ranges::in_out_result<int, int>&&, 44 std::ranges::in_out_result<long, long>>); 45 46 int main(int, char**) { 47 // Conversion, fundamental types. 48 { 49 std::ranges::in_out_result<int, bool> x = {2, false}; 50 // FIXME(varconst): try a narrowing conversion. 51 std::ranges::in_out_result<long, char> y = x; 52 assert(y.in == 2); 53 assert(y.out == '\0'); 54 } 55 56 // Conversion, user-defined types. 57 { 58 struct From1 { 59 int value = 0; 60 From1(int v) : value(v) {} 61 }; 62 63 struct To1 { 64 int value = 0; 65 To1(int v) : value(v) {} 66 67 To1(const From1& f) : value(f.value) {}; 68 }; 69 70 struct To2 { 71 int value = 0; 72 To2(int v) : value(v) {} 73 }; 74 struct From2 { 75 int value = 0; 76 From2(int v) : value(v) {} 77 78 operator To2() const { return To2(value); } 79 }; 80 81 std::ranges::in_out_result<From1, From2> x{42, 99}; 82 std::ranges::in_out_result<To1, To2> y = x; 83 assert(y.in.value == 42); 84 assert(y.out.value == 99); 85 } 86 87 // Copy-only type. 88 { 89 struct CopyOnly { 90 int value = 0; 91 CopyOnly() = default; 92 CopyOnly(int v) : value(v) {} 93 94 CopyOnly(const CopyOnly&) = default; 95 CopyOnly(CopyOnly&&) = delete; 96 }; 97 98 std::ranges::in_out_result<CopyOnly, CopyOnly> x; 99 x.in.value = 42; 100 x.out.value = 99; 101 102 auto y = x; 103 assert(y.in.value == 42); 104 assert(y.out.value == 99); 105 } 106 107 // Move-only type. 108 { 109 struct MoveOnly { 110 int value = 0; 111 MoveOnly(int v) : value(v) {} 112 113 MoveOnly(MoveOnly&&) = default; 114 MoveOnly(const MoveOnly&) = delete; 115 }; 116 117 std::ranges::in_out_result<MoveOnly, MoveOnly> x{42, 99}; 118 auto y = std::move(x); 119 assert(y.in.value == 42); 120 assert(y.out.value == 99); 121 } 122 123 // Unsuccessful conversion. 124 { 125 struct Foo1 {}; 126 struct Foo2 {}; 127 struct Bar1 {}; 128 struct Bar2 {}; 129 static_assert( 130 !std::is_convertible_v<std::ranges::in_out_result<Foo1, Foo2>, std::ranges::in_out_result<Bar1, Bar2>>); 131 } 132 133 return 0; 134 } 135