10218ea4aSZijun Zhao //===----------------------------------------------------------------------===// 20218ea4aSZijun Zhao // 30218ea4aSZijun Zhao // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40218ea4aSZijun Zhao // See https://llvm.org/LICENSE.txt for license information. 50218ea4aSZijun Zhao // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60218ea4aSZijun Zhao // 70218ea4aSZijun Zhao //===----------------------------------------------------------------------===// 80218ea4aSZijun Zhao 90218ea4aSZijun Zhao // <algorithm> 100218ea4aSZijun Zhao 110218ea4aSZijun Zhao // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 120218ea4aSZijun Zhao 130218ea4aSZijun Zhao // template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, 140218ea4aSZijun Zhao // class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> 150218ea4aSZijun Zhao // requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2> 160218ea4aSZijun Zhao // constexpr bool ranges::ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, 170218ea4aSZijun Zhao // Proj1 proj1 = {}, Proj2 proj2 = {}); 180218ea4aSZijun Zhao // template<input_range R1, input_range R2, class Pred = ranges::equal_to, class Proj1 = identity, 190218ea4aSZijun Zhao // class Proj2 = identity> 200218ea4aSZijun Zhao // requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> 210218ea4aSZijun Zhao // constexpr bool ranges::ends_with(R1&& r1, R2&& r2, Pred pred = {}, 220218ea4aSZijun Zhao // Proj1 proj1 = {}, Proj2 proj2 = {}); 230218ea4aSZijun Zhao 240218ea4aSZijun Zhao #include <algorithm> 250218ea4aSZijun Zhao #include <array> 260218ea4aSZijun Zhao #include <chrono> 270218ea4aSZijun Zhao #include <ranges> 280218ea4aSZijun Zhao #include "almost_satisfies_types.h" 290218ea4aSZijun Zhao #include "test_iterators.h" 300218ea4aSZijun Zhao 310218ea4aSZijun Zhao using namespace std::chrono; 320218ea4aSZijun Zhao 330218ea4aSZijun Zhao template <class Iter1, class Sent1 = Iter1, class Iter2 = int*, class Sent2 = Iter2> 340218ea4aSZijun Zhao concept HasEndsWithIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) { 350218ea4aSZijun Zhao std::ranges::ends_with(first1, last1, first2, last2); 360218ea4aSZijun Zhao }; 370218ea4aSZijun Zhao 380218ea4aSZijun Zhao static_assert(HasEndsWithIt<int*>); 390218ea4aSZijun Zhao static_assert(!HasEndsWithIt<ForwardIteratorNotDerivedFrom>); 400218ea4aSZijun Zhao static_assert(!HasEndsWithIt<ForwardIteratorNotIncrementable>); 410218ea4aSZijun Zhao static_assert(HasEndsWithIt<int*, int*>); 420218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, SentinelForNotSemiregular>); 430218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, int*, int**>); // not indirectly comparable 440218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, SentinelForNotWeaklyEqualityComparableWith>); 450218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, int*, ForwardIteratorNotDerivedFrom>); 460218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, int*, ForwardIteratorNotIncrementable>); 470218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotSemiregular>); 480218ea4aSZijun Zhao static_assert(!HasEndsWithIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>); 490218ea4aSZijun Zhao 500218ea4aSZijun Zhao template <class Range1, class Range2 = UncheckedRange<int*>> 510218ea4aSZijun Zhao concept HasEndsWithR = requires(Range1&& range1, Range2&& range2) { 52*f73050e7SLouis Dionne std::ranges::ends_with(std::forward<Range1>(range1), std::forward<Range2>(range2)); 53*f73050e7SLouis Dionne }; 540218ea4aSZijun Zhao 550218ea4aSZijun Zhao static_assert(HasEndsWithR<UncheckedRange<int*>>); 560218ea4aSZijun Zhao static_assert(!HasEndsWithR<ForwardRangeNotDerivedFrom>); 570218ea4aSZijun Zhao static_assert(!HasEndsWithR<ForwardIteratorNotIncrementable>); 580218ea4aSZijun Zhao static_assert(!HasEndsWithR<ForwardRangeNotSentinelSemiregular>); 590218ea4aSZijun Zhao static_assert(!HasEndsWithR<ForwardRangeNotSentinelEqualityComparableWith>); 600218ea4aSZijun Zhao static_assert(HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int*>>); 610218ea4aSZijun Zhao static_assert(!HasEndsWithR<UncheckedRange<int*>, UncheckedRange<int**>>); // not indirectly comparable 620218ea4aSZijun Zhao static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>); 630218ea4aSZijun Zhao static_assert(!HasEndsWithR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>); 640218ea4aSZijun Zhao 650218ea4aSZijun Zhao template <class Iter1, class Sent1 = Iter1, class Iter2, class Sent2 = Iter2> 660218ea4aSZijun Zhao constexpr void test_iterators() { 670218ea4aSZijun Zhao { // simple tests 680218ea4aSZijun Zhao int a[] = {1, 2, 3, 4, 5, 6}; 690218ea4aSZijun Zhao int p[] = {4, 5, 6}; 70*f73050e7SLouis Dionne { 710218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 720218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 73*f73050e7SLouis Dionne [[maybe_unused]] std::same_as<bool> decltype(auto) ret = 74*f73050e7SLouis Dionne std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 750218ea4aSZijun Zhao assert(ret); 760218ea4aSZijun Zhao } 770218ea4aSZijun Zhao { 78*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 79*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 800218ea4aSZijun Zhao [[maybe_unused]] std::same_as<bool> decltype(auto) ret = std::ranges::ends_with(whole, suffix); 810218ea4aSZijun Zhao assert(ret); 820218ea4aSZijun Zhao } 830218ea4aSZijun Zhao } 840218ea4aSZijun Zhao 850218ea4aSZijun Zhao { // suffix doesn't match 860218ea4aSZijun Zhao int a[] = {1, 2, 3, 4, 5, 6}; 870218ea4aSZijun Zhao int p[] = {1, 2, 3}; 88*f73050e7SLouis Dionne { 890218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 900218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 910218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 920218ea4aSZijun Zhao assert(!ret); 930218ea4aSZijun Zhao } 940218ea4aSZijun Zhao { 95*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 96*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 970218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 980218ea4aSZijun Zhao assert(!ret); 990218ea4aSZijun Zhao } 1000218ea4aSZijun Zhao } 1010218ea4aSZijun Zhao 1020218ea4aSZijun Zhao { // range consists of just one element 1030218ea4aSZijun Zhao int a[] = {1}; 1040218ea4aSZijun Zhao int p[] = {1}; 105*f73050e7SLouis Dionne { 1060218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); 1070218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 1080218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 1090218ea4aSZijun Zhao assert(ret); 1100218ea4aSZijun Zhao } 1110218ea4aSZijun Zhao { 112*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 1))); 113*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 1140218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 1150218ea4aSZijun Zhao assert(ret); 1160218ea4aSZijun Zhao } 1170218ea4aSZijun Zhao } 1180218ea4aSZijun Zhao 1190218ea4aSZijun Zhao { // suffix consists of just one element 1200218ea4aSZijun Zhao int a[] = {5, 1, 2, 4, 3}; 1210218ea4aSZijun Zhao int p[] = {3}; 122*f73050e7SLouis Dionne { 1230218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 1240218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 1250218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 1260218ea4aSZijun Zhao assert(ret); 1270218ea4aSZijun Zhao } 1280218ea4aSZijun Zhao { 129*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 130*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 1))); 1310218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 1320218ea4aSZijun Zhao assert(ret); 1330218ea4aSZijun Zhao } 1340218ea4aSZijun Zhao } 1350218ea4aSZijun Zhao 1360218ea4aSZijun Zhao { // range and suffix are identical 1370218ea4aSZijun Zhao int a[] = {1, 2, 3, 4, 5, 6}; 1380218ea4aSZijun Zhao int p[] = {1, 2, 3, 4, 5, 6}; 139*f73050e7SLouis Dionne { 1400218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 1410218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); 1420218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 1430218ea4aSZijun Zhao assert(ret); 1440218ea4aSZijun Zhao } 1450218ea4aSZijun Zhao { 146*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 147*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 6))); 1480218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 1490218ea4aSZijun Zhao assert(ret); 1500218ea4aSZijun Zhao } 1510218ea4aSZijun Zhao } 1520218ea4aSZijun Zhao 1530218ea4aSZijun Zhao { // suffix is longer than range 1540218ea4aSZijun Zhao int a[] = {3, 4, 5, 6, 7, 8}; 1550218ea4aSZijun Zhao int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 156*f73050e7SLouis Dionne { 1570218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 1580218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 1590218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 1600218ea4aSZijun Zhao assert(!ret); 1610218ea4aSZijun Zhao } 1620218ea4aSZijun Zhao { 163*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 164*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 1650218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 1660218ea4aSZijun Zhao assert(!ret); 1670218ea4aSZijun Zhao } 1680218ea4aSZijun Zhao } 1690218ea4aSZijun Zhao 1700218ea4aSZijun Zhao { // suffix has zero length 1710218ea4aSZijun Zhao int a[] = {1, 2, 3, 4, 5, 6}; 172c000f754SStephan T. Lavavej std::array<int, 0> p = {}; 173*f73050e7SLouis Dionne { 1740218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 175c000f754SStephan T. Lavavej auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data()))); 1760218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 1770218ea4aSZijun Zhao assert(ret); 1780218ea4aSZijun Zhao } 1790218ea4aSZijun Zhao { 180*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 181*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p.data()), Sent2(Iter2(p.data()))); 1820218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 1830218ea4aSZijun Zhao assert(ret); 1840218ea4aSZijun Zhao } 1850218ea4aSZijun Zhao } 1860218ea4aSZijun Zhao 1870218ea4aSZijun Zhao { // range has zero length 188c000f754SStephan T. Lavavej std::array<int, 0> a = {}; 1890218ea4aSZijun Zhao int p[] = {1, 2, 3, 4, 5, 6, 7, 8}; 190*f73050e7SLouis Dionne { 191c000f754SStephan T. Lavavej auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); 1920218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 1930218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 1940218ea4aSZijun Zhao assert(!ret); 1950218ea4aSZijun Zhao } 1960218ea4aSZijun Zhao { 197*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a.data()), Sent1(Iter1(a.data()))); 198*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 8))); 1990218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 2000218ea4aSZijun Zhao assert(!ret); 2010218ea4aSZijun Zhao } 2020218ea4aSZijun Zhao } 2030218ea4aSZijun Zhao 2040218ea4aSZijun Zhao { // subarray 2050218ea4aSZijun Zhao int a[] = {0, 3, 5, 10, 7, 3, 5, 89, 3, 5, 2, 1, 8, 6}; 2060218ea4aSZijun Zhao int p[] = {3, 5}; 207*f73050e7SLouis Dionne { 2080218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13))); 2090218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 2100218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 2110218ea4aSZijun Zhao assert(!ret); 2120218ea4aSZijun Zhao } 2130218ea4aSZijun Zhao { 214*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 13))); 215*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 2160218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 2170218ea4aSZijun Zhao assert(!ret); 2180218ea4aSZijun Zhao } 2190218ea4aSZijun Zhao } 2200218ea4aSZijun Zhao 2210218ea4aSZijun Zhao { // repeated suffix 2220218ea4aSZijun Zhao int a[] = {8, 6, 3, 5, 1, 2}; 2230218ea4aSZijun Zhao int p[] = {1, 2, 1, 2}; 224*f73050e7SLouis Dionne { 2250218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 2260218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4))); 2270218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end()); 2280218ea4aSZijun Zhao assert(!ret); 2290218ea4aSZijun Zhao } 2300218ea4aSZijun Zhao { 231*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 232*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 4))); 2330218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix); 2340218ea4aSZijun Zhao assert(!ret); 2350218ea4aSZijun Zhao } 2360218ea4aSZijun Zhao } 2370218ea4aSZijun Zhao 2380218ea4aSZijun Zhao { // check that the predicate is used 2390218ea4aSZijun Zhao int a[] = {5, 1, 3, 2, 7}; 2400218ea4aSZijun Zhao int p[] = {-2, -7}; 2410218ea4aSZijun Zhao auto pred = [](int l, int r) { return l * -1 == r; }; 242*f73050e7SLouis Dionne { 2430218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 2440218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 2450218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole.begin(), whole.end(), suffix.begin(), suffix.end(), pred); 2460218ea4aSZijun Zhao assert(ret); 2470218ea4aSZijun Zhao } 2480218ea4aSZijun Zhao { 249*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 5))); 250*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 2))); 2510218ea4aSZijun Zhao bool ret = std::ranges::ends_with(whole, suffix, pred); 2520218ea4aSZijun Zhao assert(ret); 2530218ea4aSZijun Zhao } 2540218ea4aSZijun Zhao } 2550218ea4aSZijun Zhao 2560218ea4aSZijun Zhao { // check that the projections are used 2570218ea4aSZijun Zhao int a[] = {1, 3, 15, 1, 2, 1}; 2580218ea4aSZijun Zhao int p[] = {2, 1, 2}; 259*f73050e7SLouis Dionne { 2600218ea4aSZijun Zhao auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 2610218ea4aSZijun Zhao auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 262*f73050e7SLouis Dionne bool ret = std::ranges::ends_with( 263*f73050e7SLouis Dionne whole.begin(), 264*f73050e7SLouis Dionne whole.end(), 265*f73050e7SLouis Dionne suffix.begin(), 266*f73050e7SLouis Dionne suffix.end(), 267*f73050e7SLouis Dionne {}, 2680218ea4aSZijun Zhao [](int i) { return i - 3; }, 2690218ea4aSZijun Zhao [](int i) { return i * -1; }); 2700218ea4aSZijun Zhao assert(ret); 2710218ea4aSZijun Zhao } 2720218ea4aSZijun Zhao { 273*f73050e7SLouis Dionne auto whole = std::ranges::subrange(Iter1(a), Sent1(Iter1(a + 6))); 274*f73050e7SLouis Dionne auto suffix = std::ranges::subrange(Iter2(p), Sent2(Iter2(p + 3))); 275*f73050e7SLouis Dionne bool ret = std::ranges::ends_with(whole, suffix, {}, [](int i) { return i - 3; }, [](int i) { return i * -1; }); 2760218ea4aSZijun Zhao assert(ret); 2770218ea4aSZijun Zhao } 2780218ea4aSZijun Zhao } 2790218ea4aSZijun Zhao } 2800218ea4aSZijun Zhao 2810218ea4aSZijun Zhao constexpr bool test() { 2820218ea4aSZijun Zhao // This is to test (forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>) condition. 2830218ea4aSZijun Zhao types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter2>() { 2840218ea4aSZijun Zhao types::for_each(types::cpp20_input_iterator_list<int*>{}, []<class Iter1>() { 2850218ea4aSZijun Zhao if constexpr (std::forward_iterator<Iter1> && std::forward_iterator<Iter2>) 2860218ea4aSZijun Zhao test_iterators<Iter1, Iter1, Iter2, Iter2>(); 2870218ea4aSZijun Zhao if constexpr (std::forward_iterator<Iter2>) 2880218ea4aSZijun Zhao test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, Iter2>(); 2890218ea4aSZijun Zhao if constexpr (std::forward_iterator<Iter1>) 2900218ea4aSZijun Zhao test_iterators<Iter1, Iter1, Iter2, sized_sentinel<Iter2>>(); 2910218ea4aSZijun Zhao test_iterators<Iter1, sized_sentinel<Iter1>, Iter2, sized_sentinel<Iter2>>(); 2920218ea4aSZijun Zhao }); 2930218ea4aSZijun Zhao }); 2940218ea4aSZijun Zhao 2950218ea4aSZijun Zhao return true; 2960218ea4aSZijun Zhao } 2970218ea4aSZijun Zhao 2980218ea4aSZijun Zhao int main(int, char**) { 2990218ea4aSZijun Zhao test(); 3000218ea4aSZijun Zhao static_assert(test()); 3010218ea4aSZijun Zhao 3020218ea4aSZijun Zhao return 0; 3030218ea4aSZijun Zhao } 304