brintos

brintos / llvm-project-archived public Read only

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