139 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++1710 11// constexpr sentinel(sentinel<!Const> s)12// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;13 14#include <cassert>15#include <ranges>16 17#include "../types.h"18 19struct Sent {20 int i;21 constexpr Sent() = default;22 constexpr Sent(int ii) : i(ii) {}23 friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; }24};25 26struct ConstSent {27 int i;28 constexpr ConstSent() = default;29 constexpr ConstSent(int ii) : i(ii) {}30 constexpr ConstSent(const Sent& s) : i(s.i) {}31 friend constexpr bool operator==(int* iter, const ConstSent& s) { return s.i > *iter; }32};33 34struct Range : std::ranges::view_base {35 int* begin() const;36 Sent end();37 ConstSent end() const;38};39 40struct Pred {41 bool operator()(int i) const;42};43 44struct NonConvertConstSent {45 int i;46 constexpr NonConvertConstSent() = default;47 constexpr NonConvertConstSent(int ii) : i(ii) {}48 friend constexpr bool operator==(int* iter, const NonConvertConstSent& s) { return s.i > *iter; }49};50 51struct NonConvertConstSentRange : std::ranges::view_base {52 int* begin() const;53 Sent end();54 NonConvertConstSent end() const;55};56 57// Test Constraint58static_assert(std::is_constructible_v<std::ranges::sentinel_t<const std::ranges::take_while_view<Range, Pred>>,59 std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>>);60 61// !Const62static_assert(!std::is_constructible_v<std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>,63 std::ranges::sentinel_t<const std::ranges::take_while_view<Range, Pred>>>);64 65// !convertible_to<sentinel_t<V>, sentinel_t<Base>>66static_assert(!std::is_constructible_v<67 std::ranges::sentinel_t<const std::ranges::take_while_view<NonConvertConstSentRange, Pred>>,68 std::ranges::sentinel_t<std::ranges::take_while_view<NonConvertConstSentRange, Pred>>>);69 70constexpr bool test() {71 // base is init correctly72 {73 using R = std::ranges::take_while_view<Range, bool (*)(int)>;74 using Sentinel = std::ranges::sentinel_t<R>;75 using ConstSentinel = std::ranges::sentinel_t<const R>;76 static_assert(!std::same_as<Sentinel, ConstSentinel>);77 78 Sentinel s1(Sent{5}, nullptr);79 ConstSentinel s2 = s1;80 assert(s2.base().i == 5);81 }82 83 // pred is init correctly84 {85 bool called = false;86 auto pred = [&](int) {87 called = true;88 return false;89 };90 91 using R = std::ranges::take_while_view<Range, decltype(pred)>;92 using Sentinel = std::ranges::sentinel_t<R>;93 using ConstSentinel = std::ranges::sentinel_t<const R>;94 static_assert(!std::same_as<Sentinel, ConstSentinel>);95 96 int i = 10;97 int* iter = &i;98 Sentinel s1(Sent{0}, &pred);99 ConstSentinel s2 = s1;100 101 [[maybe_unused]] bool b = iter == s2;102 assert(called);103 }104 105 // LWG 3708 `take_while_view::sentinel`'s conversion constructor should move106 {107 struct MoveOnlyConvert {108 int i;109 constexpr MoveOnlyConvert() = default;110 constexpr MoveOnlyConvert(Sent&& s) : i(s.i) { s.i = 0; }111 constexpr bool operator==(int* iter) const { return i > *iter; }112 };113 114 struct Rng : std::ranges::view_base {115 int* begin() const;116 Sent end();117 MoveOnlyConvert end() const;118 };119 120 using R = std::ranges::take_while_view<Rng, Pred>;121 using Sentinel = std::ranges::sentinel_t<R>;122 using ConstSentinel = std::ranges::sentinel_t<const R>;123 static_assert(!std::same_as<Sentinel, ConstSentinel>);124 125 Sentinel s1(Sent{5}, nullptr);126 ConstSentinel s2 = s1;127 assert(s2.base().i == 5);128 }129 130 return true;131}132 133int main(int, char**) {134 test();135 static_assert(test());136 137 return 0;138}139