142 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++2010 11// template <class O, class T>12// struct out_value_result;13 14#include <algorithm>15#include <cassert>16#include <type_traits>17 18#include "MoveOnly.h"19 20using std::ranges::out_value_result;21 22//23// Helper structs24//25 26// only explicit construction27struct IterTypeExplicit {28 explicit IterTypeExplicit(int*);29};30 31// implicit construction32struct IterTypeImplicit {33 IterTypeImplicit(int*);34};35 36struct IterTypeImplicitRef {37 IterTypeImplicitRef(int&);38};39 40struct NotConvertible {};41 42template <class T>43struct ConvertibleFrom {44 constexpr ConvertibleFrom(T c) : content{c} {}45 T content;46};47 48// Standard layout classes can't have virtual functions49struct NonStandardLayoutTypeBase {50 virtual ~NonStandardLayoutTypeBase();51};52struct NonStandardLayoutType : public NonStandardLayoutTypeBase {};53 54//55constexpr bool test_constraints() {56 // requires convertible_to<const _OutIter1&, _OutIter2> && convertible_to<const _ValType1&, _ValType2>57 static_assert(std::is_constructible_v<out_value_result<int*, int>, out_value_result<int*, int>>);58 59 // test failure when implicit conversion isn't allowed60 static_assert(!std::is_constructible_v<out_value_result<IterTypeExplicit, int>, out_value_result<int*, int>>);61 62 // test success when implicit conversion is allowed, checking combinations of value, reference, and const63 static_assert(std::is_constructible_v<out_value_result<IterTypeImplicit, int>, out_value_result<int*, int>>);64 static_assert(std::is_constructible_v<out_value_result<IterTypeImplicit, int>, out_value_result<int*, int> const>);65 static_assert(std::is_constructible_v<out_value_result<IterTypeImplicit, int>, out_value_result<int*, int>&>);66 static_assert(std::is_constructible_v<out_value_result<IterTypeImplicit, int>, out_value_result<int*, int> const&>);67 68 static_assert(!std::is_constructible_v<out_value_result<IterTypeImplicitRef, int>, out_value_result<int, int>&>);69 70 // has to be convertible via const&71 static_assert(std::is_convertible_v<out_value_result<int, int>&, out_value_result<long, long>>);72 static_assert(std::is_convertible_v<const out_value_result<int, int>&, out_value_result<long, long>>);73 static_assert(std::is_convertible_v<out_value_result<int, int>&&, out_value_result<long, long>>);74 static_assert(std::is_convertible_v<const out_value_result<int, int>&&, out_value_result<long, long>>);75 76 // should be move constructible77 static_assert(std::is_move_constructible_v<out_value_result<MoveOnly, int>>);78 static_assert(std::is_move_constructible_v<out_value_result<int, MoveOnly>>);79 80 // conversions should not work if there is no conversion81 static_assert(!std::is_convertible_v<out_value_result<NotConvertible, int>, out_value_result<int, NotConvertible>>);82 static_assert(!std::is_convertible_v<out_value_result<int, NotConvertible>, out_value_result<NotConvertible, int>>);83 84 // check standard layout85 static_assert(std::is_standard_layout_v<out_value_result<int, int>>);86 static_assert(!std::is_standard_layout_v<out_value_result<NonStandardLayoutType, int>>);87 88 return true;89}90 91// Test results92constexpr bool test() {93 {94 // Check that conversion operator works95 out_value_result<double, int> res{10, 1};96 assert(res.out == 10);97 assert(res.value == 1);98 out_value_result<ConvertibleFrom<double>, ConvertibleFrom<int>> res2 = res;99 assert(res2.out.content == 10);100 assert(res2.value.content == 1);101 }102 {103 // Check that out_value_result isn't overconstrained w.r.t. move/copy constructors104 out_value_result<MoveOnly, int> res{MoveOnly{}, 10};105 assert(res.out.get() == 1);106 assert(res.value == 10);107 auto res2 = std::move(res);108 assert(res.out.get() == 0);109 assert(res.value == 10);110 assert(res2.out.get() == 1);111 assert(res2.value == 10);112 }113 {114 // Check structured binding115 auto [out, val] = out_value_result<int, int>{1, 2};116 assert(out == 1);117 assert(val == 2);118 }119 {120 // Check default construction121 out_value_result<int, double> res;122 static_assert(std::is_same_v<int, decltype(res.out)>);123 static_assert(std::is_same_v<double, decltype(res.value)>);124 }125 {126 // Check aggregate initialization127 out_value_result<int, int> res = {1, 2};128 assert(res.out == 1);129 assert(res.value == 2);130 }131 132 return true;133}134 135int main(int, char**) {136 test_constraints();137 static_assert(test_constraints());138 test();139 static_assert(test());140 return 0;141}142