522 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// std::ranges::rbegin12// std::ranges::crbegin13 14#include <ranges>15 16#include <cassert>17#include <utility>18#include "test_macros.h"19#include "test_iterators.h"20 21using RangeRBeginT = decltype(std::ranges::rbegin);22using RangeCRBeginT = decltype(std::ranges::crbegin);23 24static int globalBuff[8];25 26static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[10]>);27static_assert( std::is_invocable_v<RangeRBeginT, int (&)[10]>);28static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[]>);29static_assert(!std::is_invocable_v<RangeRBeginT, int (&)[]>);30static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);31static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);32static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);33static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);34 35struct Incomplete;36 37static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[]>);38static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[]>);39static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[]>);40static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[]>);41 42static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[10]>);43static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[10]>);44static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);45static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);46 47// This case is IFNDR; we handle it SFINAE-friendly.48LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[]>);49LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[]>);50LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);51LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);52 53// This case is IFNDR; we handle it SFINAE-friendly.54LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[10]>);55LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[10]>);56LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);57LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);58 59struct RBeginMember {60 int x;61 constexpr const int *rbegin() const { return &x; }62};63 64// Ensure that we can't call with rvalues with borrowing disabled.65static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember &>);66static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember &&>);67static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember const&>);68static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember const&&>);69static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember &>);70static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember &&>);71static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember const&>);72static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember const&&>);73 74constexpr bool testReturnTypes() {75 {76 int *x[2];77 ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int**>);78 ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<int* const*>);79 }80 {81 int x[2][2];82 ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int(*)[2]>);83 ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<const int(*)[2]>);84 }85 {86 struct Different {87 char*& rbegin();88 short*& rbegin() const;89 } x;90 ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), char*);91 ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), short*);92 }93 return true;94}95 96constexpr bool testArray() {97 int a[2];98 assert(std::ranges::rbegin(a).base() == a + 2);99 assert(std::ranges::crbegin(a).base() == a + 2);100 101 int b[2][2];102 assert(std::ranges::rbegin(b).base() == b + 2);103 assert(std::ranges::crbegin(b).base() == b + 2);104 105 RBeginMember c[2];106 assert(std::ranges::rbegin(c).base() == c + 2);107 assert(std::ranges::crbegin(c).base() == c + 2);108 109 return true;110}111 112struct RBeginMemberReturnsInt {113 int rbegin() const;114};115static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMemberReturnsInt const&>);116 117struct RBeginMemberReturnsVoidPtr {118 const void *rbegin() const;119};120static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMemberReturnsVoidPtr const&>);121 122struct PtrConvertibleRBeginMember {123 struct iterator { operator int*() const; };124 iterator rbegin() const;125};126static_assert(!std::is_invocable_v<RangeRBeginT, PtrConvertibleRBeginMember const&>);127 128struct NonConstRBeginMember {129 int x;130 constexpr int* rbegin() { return &x; }131};132static_assert( std::is_invocable_v<RangeRBeginT, NonConstRBeginMember &>);133static_assert(!std::is_invocable_v<RangeRBeginT, NonConstRBeginMember const&>);134static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember &>);135static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember const&>);136 137struct EnabledBorrowingRBeginMember {138 constexpr int *rbegin() const { return globalBuff; }139};140template<>141inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingRBeginMember> = true;142 143struct RBeginMemberFunction {144 int x;145 constexpr const int *rbegin() const { return &x; }146 friend int* rbegin(RBeginMemberFunction const&);147};148 149struct EmptyPtrRBeginMember {150 struct Empty {};151 Empty x;152 constexpr const Empty* rbegin() const { return &x; }153};154 155constexpr bool testRBeginMember() {156 RBeginMember a;157 assert(std::ranges::rbegin(a) == &a.x);158 assert(std::ranges::crbegin(a) == &a.x);159 static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember&&>);160 static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember&&>);161 162 NonConstRBeginMember b;163 assert(std::ranges::rbegin(b) == &b.x);164 static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember&>);165 166 EnabledBorrowingRBeginMember c;167 assert(std::ranges::rbegin(c) == globalBuff);168 assert(std::ranges::crbegin(c) == globalBuff);169 assert(std::ranges::rbegin(std::move(c)) == globalBuff);170 assert(std::ranges::crbegin(std::move(c)) == globalBuff);171 172 RBeginMemberFunction d;173 assert(std::ranges::rbegin(d) == &d.x);174 assert(std::ranges::crbegin(d) == &d.x);175 176 EmptyPtrRBeginMember e;177 assert(std::ranges::rbegin(e) == &e.x);178 assert(std::ranges::crbegin(e) == &e.x);179 180 return true;181}182 183 184struct RBeginFunction {185 int x;186 friend constexpr const int* rbegin(RBeginFunction const& bf) { return &bf.x; }187};188static_assert( std::is_invocable_v<RangeRBeginT, RBeginFunction const&>);189static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunction &&>);190static_assert(191 std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic192static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);193static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);194 195struct RBeginFunctionReturnsInt {196 friend int rbegin(RBeginFunctionReturnsInt const&);197};198static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsInt const&>);199 200struct RBeginFunctionReturnsVoidPtr {201 friend void *rbegin(RBeginFunctionReturnsVoidPtr const&);202};203static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsVoidPtr const&>);204 205struct RBeginFunctionReturnsEmpty {206 struct Empty {};207 friend Empty rbegin(RBeginFunctionReturnsEmpty const&);208};209static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsEmpty const&>);210 211struct RBeginFunctionReturnsPtrConvertible {212 struct iterator { operator int*() const; };213 friend iterator rbegin(RBeginFunctionReturnsPtrConvertible const&);214};215static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsPtrConvertible const&>);216 217struct RBeginFunctionByValue {218 friend constexpr int *rbegin(RBeginFunctionByValue) { return globalBuff + 1; }219};220static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginFunctionByValue>);221 222struct RBeginFunctionEnabledBorrowing {223 friend constexpr int *rbegin(RBeginFunctionEnabledBorrowing) { return globalBuff + 2; }224};225template<>226inline constexpr bool std::ranges::enable_borrowed_range<RBeginFunctionEnabledBorrowing> = true;227 228struct RBeginFunctionReturnsEmptyPtr {229 struct Empty {};230 Empty x;231 friend constexpr const Empty *rbegin(RBeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }232};233 234struct RBeginFunctionWithDataMember {235 int x;236 int rbegin;237 friend constexpr const int *rbegin(RBeginFunctionWithDataMember const& bf) { return &bf.x; }238};239 240struct RBeginFunctionWithPrivateBeginMember {241 int y;242 friend constexpr const int *rbegin(RBeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }243private:244 const int *rbegin() const;245};246 247constexpr bool testRBeginFunction() {248 RBeginFunction a{};249 const RBeginFunction aa{};250 assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic251 assert(std::ranges::crbegin(a) == &a.x);252 assert(std::ranges::rbegin(aa) == &aa.x);253 assert(std::ranges::crbegin(aa) == &aa.x);254 255 RBeginFunctionByValue b{};256 const RBeginFunctionByValue bb{};257 assert(std::ranges::rbegin(b) == globalBuff + 1);258 assert(std::ranges::crbegin(b) == globalBuff + 1);259 assert(std::ranges::rbegin(bb) == globalBuff + 1);260 assert(std::ranges::crbegin(bb) == globalBuff + 1);261 262 RBeginFunctionEnabledBorrowing c{};263 const RBeginFunctionEnabledBorrowing cc{};264 assert(std::ranges::rbegin(std::move(c)) == globalBuff + 2);265 assert(std::ranges::crbegin(std::move(c)) == globalBuff + 2);266 assert(std::ranges::rbegin(std::move(cc)) == globalBuff + 2);267 assert(std::ranges::crbegin(std::move(cc)) == globalBuff + 2);268 269 RBeginFunctionReturnsEmptyPtr d{};270 const RBeginFunctionReturnsEmptyPtr dd{};271 assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic272 assert(std::ranges::crbegin(d) == &d.x);273 assert(std::ranges::rbegin(dd) == &dd.x);274 assert(std::ranges::crbegin(dd) == &dd.x);275 276 RBeginFunctionWithDataMember e{};277 const RBeginFunctionWithDataMember ee{};278 assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic279 assert(std::ranges::rbegin(ee) == &ee.x);280 assert(std::ranges::crbegin(e) == &e.x);281 assert(std::ranges::crbegin(ee) == &ee.x);282 283 RBeginFunctionWithPrivateBeginMember f{};284 const RBeginFunctionWithPrivateBeginMember ff{};285 assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic286 assert(std::ranges::crbegin(f) == &f.y);287 assert(std::ranges::rbegin(ff) == &ff.y);288 assert(std::ranges::crbegin(ff) == &ff.y);289 290 return true;291}292 293 294struct MemberBeginEnd {295 int b, e;296 char cb, ce;297 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }298 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }299 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }300 constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); }301};302static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd&>);303static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd const&>);304static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginEnd const&>);305 306struct FunctionBeginEnd {307 int b, e;308 char cb, ce;309 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginEnd& v) {310 return bidirectional_iterator<int*>(&v.b);311 }312 friend constexpr bidirectional_iterator<int*> end(FunctionBeginEnd& v) { return bidirectional_iterator<int*>(&v.e); }313 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginEnd& v) {314 return bidirectional_iterator<const char*>(&v.cb);315 }316 friend constexpr bidirectional_iterator<const char*> end(const FunctionBeginEnd& v) {317 return bidirectional_iterator<const char*>(&v.ce);318 }319};320static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd&>);321static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd const&>);322static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginEnd const&>);323 324struct MemberBeginFunctionEnd {325 int b, e;326 char cb, ce;327 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }328 friend constexpr bidirectional_iterator<int*> end(MemberBeginFunctionEnd& v) {329 return bidirectional_iterator<int*>(&v.e);330 }331 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }332 friend constexpr bidirectional_iterator<const char*> end(const MemberBeginFunctionEnd& v) {333 return bidirectional_iterator<const char*>(&v.ce);334 }335};336static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd&>);337static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd const&>);338static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginFunctionEnd const&>);339 340struct FunctionBeginMemberEnd {341 int b, e;342 char cb, ce;343 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginMemberEnd& v) {344 return bidirectional_iterator<int*>(&v.b);345 }346 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }347 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginMemberEnd& v) {348 return bidirectional_iterator<const char*>(&v.cb);349 }350 constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); }351};352static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd&>);353static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd const&>);354static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginMemberEnd const&>);355 356struct MemberBeginEndDifferentTypes {357 bidirectional_iterator<int*> begin();358 bidirectional_iterator<const int*> end();359};360static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndDifferentTypes&>);361static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndDifferentTypes&>);362 363struct FunctionBeginEndDifferentTypes {364 friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);365 friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);366};367static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndDifferentTypes&>);368static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndDifferentTypes&>);369 370struct MemberBeginEndForwardIterators {371 forward_iterator<int*> begin();372 forward_iterator<int*> end();373};374static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndForwardIterators&>);375static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndForwardIterators&>);376 377struct FunctionBeginEndForwardIterators {378 friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);379 friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);380};381static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndForwardIterators&>);382static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndForwardIterators&>);383 384struct MemberBeginOnly {385 bidirectional_iterator<int*> begin() const;386};387static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginOnly&>);388static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginOnly&>);389 390struct FunctionBeginOnly {391 friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);392};393static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginOnly&>);394static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginOnly&>);395 396struct MemberEndOnly {397 bidirectional_iterator<int*> end() const;398};399static_assert(!std::is_invocable_v<RangeRBeginT, MemberEndOnly&>);400static_assert(!std::is_invocable_v<RangeCRBeginT, MemberEndOnly&>);401 402struct FunctionEndOnly {403 friend bidirectional_iterator<int*> end(FunctionEndOnly&);404};405static_assert(!std::is_invocable_v<RangeRBeginT, FunctionEndOnly&>);406static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionEndOnly&>);407 408// Make sure there is no clash between the following cases:409// - the case that handles classes defining member `rbegin` and `rend` functions;410// - the case that handles classes defining `begin` and `end` functions returning reversible iterators.411struct MemberBeginAndRBegin {412 int* begin() const;413 int* end() const;414 int* rbegin() const;415 int* rend() const;416};417static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginAndRBegin&>);418static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginAndRBegin&>);419static_assert( std::same_as<std::invoke_result_t<RangeRBeginT, MemberBeginAndRBegin&>, int*>);420static_assert( std::same_as<std::invoke_result_t<RangeCRBeginT, MemberBeginAndRBegin&>, int*>);421 422constexpr bool testBeginEnd() {423 MemberBeginEnd a{};424 const MemberBeginEnd aa{};425 assert(base(std::ranges::rbegin(a).base()) == &a.e);426 assert(base(std::ranges::crbegin(a).base()) == &a.ce);427 assert(base(std::ranges::rbegin(aa).base()) == &aa.ce);428 assert(base(std::ranges::crbegin(aa).base()) == &aa.ce);429 430 FunctionBeginEnd b{};431 const FunctionBeginEnd bb{};432 assert(base(std::ranges::rbegin(b).base()) == &b.e);433 assert(base(std::ranges::crbegin(b).base()) == &b.ce);434 assert(base(std::ranges::rbegin(bb).base()) == &bb.ce);435 assert(base(std::ranges::crbegin(bb).base()) == &bb.ce);436 437 MemberBeginFunctionEnd c{};438 const MemberBeginFunctionEnd cc{};439 assert(base(std::ranges::rbegin(c).base()) == &c.e);440 assert(base(std::ranges::crbegin(c).base()) == &c.ce);441 assert(base(std::ranges::rbegin(cc).base()) == &cc.ce);442 assert(base(std::ranges::crbegin(cc).base()) == &cc.ce);443 444 FunctionBeginMemberEnd d{};445 const FunctionBeginMemberEnd dd{};446 assert(base(std::ranges::rbegin(d).base()) == &d.e);447 assert(base(std::ranges::crbegin(d).base()) == &d.ce);448 assert(base(std::ranges::rbegin(dd).base()) == &dd.ce);449 assert(base(std::ranges::crbegin(dd).base()) == &dd.ce);450 451 return true;452}453 454 455ASSERT_NOEXCEPT(std::ranges::rbegin(std::declval<int (&)[10]>()));456ASSERT_NOEXCEPT(std::ranges::crbegin(std::declval<int (&)[10]>()));457 458struct NoThrowMemberRBegin {459 ThrowingIterator<int> rbegin() const noexcept; // auto(t.rbegin()) doesn't throw460} ntmb;461static_assert(noexcept(std::ranges::rbegin(ntmb)));462static_assert(noexcept(std::ranges::crbegin(ntmb)));463 464struct NoThrowADLRBegin {465 friend ThrowingIterator<int> rbegin(NoThrowADLRBegin&) noexcept; // auto(rbegin(t)) doesn't throw466 friend ThrowingIterator<int> rbegin(const NoThrowADLRBegin&) noexcept;467} ntab;468static_assert(noexcept(std::ranges::rbegin(ntab)));469static_assert(noexcept(std::ranges::crbegin(ntab)));470 471struct NoThrowMemberRBeginReturnsRef {472 ThrowingIterator<int>& rbegin() const noexcept; // auto(t.rbegin()) may throw473} ntmbrr;474static_assert(!noexcept(std::ranges::rbegin(ntmbrr)));475static_assert(!noexcept(std::ranges::crbegin(ntmbrr)));476 477struct RBeginReturnsArrayRef {478 auto rbegin() const noexcept -> int(&)[10];479} brar;480static_assert(noexcept(std::ranges::rbegin(brar)));481static_assert(noexcept(std::ranges::crbegin(brar)));482 483struct NoThrowBeginThrowingEnd {484 int* begin() const noexcept;485 int* end() const;486} ntbte;487static_assert(!noexcept(std::ranges::rbegin(ntbte)));488static_assert(!noexcept(std::ranges::crbegin(ntbte)));489 490struct NoThrowEndThrowingBegin {491 int* begin() const;492 int* end() const noexcept;493} ntetb;494static_assert(noexcept(std::ranges::rbegin(ntetb)));495static_assert(noexcept(std::ranges::crbegin(ntetb)));496 497// Test ADL-proofing.498struct Incomplete;499template<class T> struct Holder { T t; };500static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*>);501static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*&>);502static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);503static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);504 505int main(int, char**) {506 static_assert(testReturnTypes());507 508 testArray();509 static_assert(testArray());510 511 testRBeginMember();512 static_assert(testRBeginMember());513 514 testRBeginFunction();515 static_assert(testRBeginFunction());516 517 testBeginEnd();518 static_assert(testBeginEnd());519 520 return 0;521}522