2021-04-11 13:08:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
|
|
|
// UNSUPPORTED: libcpp-no-concepts
|
|
|
|
|
|
|
|
// std::ranges::begin
|
2021-12-23 11:36:42 +08:00
|
|
|
// std::ranges::cbegin
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
#include <ranges>
|
|
|
|
|
|
|
|
#include <cassert>
|
2022-02-12 07:15:10 +08:00
|
|
|
#include <utility>
|
2021-04-11 13:08:32 +08:00
|
|
|
#include "test_macros.h"
|
|
|
|
#include "test_iterators.h"
|
|
|
|
|
2021-12-23 11:36:42 +08:00
|
|
|
using RangeBeginT = decltype(std::ranges::begin);
|
|
|
|
using RangeCBeginT = decltype(std::ranges::cbegin);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
static int globalBuff[8];
|
|
|
|
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[10]>);
|
|
|
|
static_assert( std::is_invocable_v<RangeBeginT, int (&)[10]>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[]>);
|
|
|
|
static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>);
|
2022-02-12 07:15:10 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
|
|
|
|
static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
|
|
|
|
static_assert( std::is_invocable_v<RangeCBeginT, int (&)[]>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
[libc++] [ranges] Remove the static_assert from ranges::begin and ranges::end.
As discussed with ldionne. The problem with this static_assert
is that it makes ranges::begin a pitfall for anyone ever to use
inside a constraint or decltype. Many Ranges things, such as ranges::size,
are specified as "Does X if X is well-formed, or else Y if Y is well-formed,
or else `ranges::end(t) - ranges::begin(t)` if that is well-formed, or else..."
And if there's a static_assert hidden inside `ranges::begin(t)`, then you get
a hard error as soon as you ask the question -- even if the answer would have
been "no, that's not well-formed"!
Constraining on `requires { t + 0; }` or `requires { t + N; }` is verboten
because of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103700 . For ranges::begin,
we can just decay to a pointer even in the incomplete-type case. For ranges::end,
we can safely constrain on `sizeof(*t)`. Yes, this means that an array of incomplete
type has a `ranges::begin` but no `ranges::end`... just like an unbounded array of
complete type. This is a valid manifestation of IFNDR.
All of the new libcxx/test/std/ cases are mandatory behavior, as far as I'm aware.
Tests for the IFNDR cases in ranges::begin and ranges::end remain in `libcxx/test/libcxx/`.
The similar tests for ranges::empty and ranges::data were simply wrong, AFAIK.
Differential Revision: https://reviews.llvm.org/D115838
2021-12-16 11:10:34 +08:00
|
|
|
struct Incomplete;
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>);
|
2022-02-04 10:41:30 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[]>);
|
[libc++] [ranges] Remove the static_assert from ranges::begin and ranges::end.
As discussed with ldionne. The problem with this static_assert
is that it makes ranges::begin a pitfall for anyone ever to use
inside a constraint or decltype. Many Ranges things, such as ranges::size,
are specified as "Does X if X is well-formed, or else Y if Y is well-formed,
or else `ranges::end(t) - ranges::begin(t)` if that is well-formed, or else..."
And if there's a static_assert hidden inside `ranges::begin(t)`, then you get
a hard error as soon as you ask the question -- even if the answer would have
been "no, that's not well-formed"!
Constraining on `requires { t + 0; }` or `requires { t + N; }` is verboten
because of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103700 . For ranges::begin,
we can just decay to a pointer even in the incomplete-type case. For ranges::end,
we can safely constrain on `sizeof(*t)`. Yes, this means that an array of incomplete
type has a `ranges::begin` but no `ranges::end`... just like an unbounded array of
complete type. This is a valid manifestation of IFNDR.
All of the new libcxx/test/std/ cases are mandatory behavior, as far as I'm aware.
Tests for the IFNDR cases in ranges::begin and ranges::end remain in `libcxx/test/libcxx/`.
The similar tests for ranges::empty and ranges::data were simply wrong, AFAIK.
Differential Revision: https://reviews.llvm.org/D115838
2021-12-16 11:10:34 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
|
2022-02-04 10:41:30 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[]>);
|
|
|
|
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[10]>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[10]>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
|
|
|
|
|
|
|
|
// This case is IFNDR; we handle it SFINAE-friendly.
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[]>);
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[]>);
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
|
|
|
|
|
|
|
|
// This case is IFNDR; we handle it SFINAE-friendly.
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[10]>);
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[10]>);
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
|
|
|
|
LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
|
[libc++] [ranges] Remove the static_assert from ranges::begin and ranges::end.
As discussed with ldionne. The problem with this static_assert
is that it makes ranges::begin a pitfall for anyone ever to use
inside a constraint or decltype. Many Ranges things, such as ranges::size,
are specified as "Does X if X is well-formed, or else Y if Y is well-formed,
or else `ranges::end(t) - ranges::begin(t)` if that is well-formed, or else..."
And if there's a static_assert hidden inside `ranges::begin(t)`, then you get
a hard error as soon as you ask the question -- even if the answer would have
been "no, that's not well-formed"!
Constraining on `requires { t + 0; }` or `requires { t + N; }` is verboten
because of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103700 . For ranges::begin,
we can just decay to a pointer even in the incomplete-type case. For ranges::end,
we can safely constrain on `sizeof(*t)`. Yes, this means that an array of incomplete
type has a `ranges::begin` but no `ranges::end`... just like an unbounded array of
complete type. This is a valid manifestation of IFNDR.
All of the new libcxx/test/std/ cases are mandatory behavior, as far as I'm aware.
Tests for the IFNDR cases in ranges::begin and ranges::end remain in `libcxx/test/libcxx/`.
The similar tests for ranges::empty and ranges::data were simply wrong, AFAIK.
Differential Revision: https://reviews.llvm.org/D115838
2021-12-16 11:10:34 +08:00
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
struct BeginMember {
|
|
|
|
int x;
|
|
|
|
constexpr const int *begin() const { return &x; }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Ensure that we can't call with rvalues with borrowing disabled.
|
2021-06-14 22:25:13 +08:00
|
|
|
static_assert( std::is_invocable_v<RangeBeginT, BeginMember &>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginMember &&>);
|
|
|
|
static_assert( std::is_invocable_v<RangeBeginT, BeginMember const&>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginMember const&&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
|
2021-06-14 22:25:13 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember &&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
|
2022-01-11 12:37:01 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember const&&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
2021-12-23 11:36:42 +08:00
|
|
|
constexpr bool testReturnTypes() {
|
|
|
|
{
|
|
|
|
int *x[2];
|
|
|
|
ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int**);
|
|
|
|
ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), int* const*);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
int x[2][2];
|
|
|
|
ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int(*)[2]);
|
|
|
|
ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), const int(*)[2]);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
struct Different {
|
|
|
|
char*& begin();
|
|
|
|
short*& begin() const;
|
|
|
|
} x;
|
|
|
|
ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), char*);
|
|
|
|
ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), short*);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
constexpr bool testArray() {
|
|
|
|
int a[2];
|
|
|
|
assert(std::ranges::begin(a) == a);
|
|
|
|
assert(std::ranges::cbegin(a) == a);
|
|
|
|
|
|
|
|
int b[2][2];
|
|
|
|
assert(std::ranges::begin(b) == b);
|
|
|
|
assert(std::ranges::cbegin(b) == b);
|
|
|
|
|
|
|
|
BeginMember c[2];
|
|
|
|
assert(std::ranges::begin(c) == c);
|
|
|
|
assert(std::ranges::cbegin(c) == c);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct BeginMemberReturnsInt {
|
|
|
|
int begin() const;
|
|
|
|
};
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsInt const&>);
|
|
|
|
|
|
|
|
struct BeginMemberReturnsVoidPtr {
|
|
|
|
const void *begin() const;
|
|
|
|
};
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsVoidPtr const&>);
|
|
|
|
|
|
|
|
struct EmptyBeginMember {
|
2021-06-14 22:25:13 +08:00
|
|
|
struct iterator {};
|
|
|
|
iterator begin() const;
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
2021-06-14 22:25:13 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, EmptyBeginMember const&>);
|
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
struct PtrConvertibleBeginMember {
|
2021-06-14 22:25:13 +08:00
|
|
|
struct iterator { operator int*() const; };
|
|
|
|
iterator begin() const;
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, PtrConvertibleBeginMember const&>);
|
|
|
|
|
|
|
|
struct NonConstBeginMember {
|
|
|
|
int x;
|
|
|
|
constexpr int *begin() { return &x; }
|
|
|
|
};
|
|
|
|
static_assert( std::is_invocable_v<RangeBeginT, NonConstBeginMember &>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, NonConstBeginMember const&>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
|
|
|
|
|
|
|
|
struct EnabledBorrowingBeginMember {
|
|
|
|
constexpr int *begin() const { return &globalBuff[0]; }
|
|
|
|
};
|
|
|
|
template<>
|
|
|
|
inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingBeginMember> = true;
|
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginMemberFunction {
|
|
|
|
int x;
|
|
|
|
constexpr const int *begin() const { return &x; }
|
|
|
|
friend int *begin(BeginMemberFunction const&);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EmptyPtrBeginMember {
|
|
|
|
struct Empty {};
|
|
|
|
Empty x;
|
|
|
|
constexpr const Empty *begin() const { return &x; }
|
|
|
|
};
|
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
constexpr bool testBeginMember() {
|
|
|
|
BeginMember a;
|
|
|
|
assert(std::ranges::begin(a) == &a.x);
|
|
|
|
assert(std::ranges::cbegin(a) == &a.x);
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginMember&&>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember&&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
NonConstBeginMember b;
|
|
|
|
assert(std::ranges::begin(b) == &b.x);
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
EnabledBorrowingBeginMember c;
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::begin(c) == &globalBuff[0]);
|
|
|
|
assert(std::ranges::cbegin(c) == &globalBuff[0]);
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::begin(std::move(c)) == &globalBuff[0]);
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
BeginMemberFunction d;
|
|
|
|
assert(std::ranges::begin(d) == &d.x);
|
|
|
|
assert(std::ranges::cbegin(d) == &d.x);
|
|
|
|
|
|
|
|
EmptyPtrBeginMember e;
|
|
|
|
assert(std::ranges::begin(e) == &e.x);
|
|
|
|
assert(std::ranges::cbegin(e) == &e.x);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-14 22:25:13 +08:00
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
struct BeginFunction {
|
|
|
|
int x;
|
|
|
|
friend constexpr const int *begin(BeginFunction const& bf) { return &bf.x; }
|
|
|
|
};
|
|
|
|
static_assert( std::is_invocable_v<RangeBeginT, BeginFunction const&>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &&>);
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &>);
|
|
|
|
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
|
|
|
|
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
|
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginFunctionReturnsInt {
|
|
|
|
friend int begin(BeginFunctionReturnsInt const&);
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
2022-02-12 07:15:10 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsInt const&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginFunctionReturnsVoidPtr {
|
|
|
|
friend void *begin(BeginFunctionReturnsVoidPtr const&);
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
2022-02-12 07:15:10 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsVoidPtr const&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginFunctionReturnsPtrConvertible {
|
|
|
|
struct iterator { operator int*() const; };
|
|
|
|
friend iterator begin(BeginFunctionReturnsPtrConvertible const&);
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
2022-02-12 07:15:10 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertible const&>);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
struct BeginFunctionByValue {
|
|
|
|
friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; }
|
|
|
|
};
|
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, BeginFunctionByValue>);
|
|
|
|
|
|
|
|
struct BeginFunctionEnabledBorrowing {
|
|
|
|
friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
|
|
|
|
};
|
|
|
|
template<>
|
|
|
|
inline constexpr bool std::ranges::enable_borrowed_range<BeginFunctionEnabledBorrowing> = true;
|
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginFunctionReturnsEmptyPtr {
|
|
|
|
struct Empty {};
|
|
|
|
Empty x;
|
|
|
|
friend constexpr const Empty *begin(BeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginFunctionWithDataMember {
|
|
|
|
int x;
|
|
|
|
int begin;
|
|
|
|
friend constexpr const int *begin(BeginFunctionWithDataMember const& bf) { return &bf.x; }
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
|
|
|
|
2022-02-12 07:15:10 +08:00
|
|
|
struct BeginFunctionWithPrivateBeginMember {
|
|
|
|
int y;
|
|
|
|
friend constexpr const int *begin(BeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }
|
|
|
|
private:
|
|
|
|
const int *begin() const;
|
2021-04-11 13:08:32 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
constexpr bool testBeginFunction() {
|
2021-06-14 22:25:13 +08:00
|
|
|
BeginFunction a{};
|
|
|
|
const BeginFunction aa{};
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(!std::invocable<RangeBeginT, decltype((a))>);
|
2021-06-14 22:25:13 +08:00
|
|
|
assert(std::ranges::cbegin(a) == &a.x);
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::begin(aa) == &aa.x);
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::cbegin(aa) == &aa.x);
|
|
|
|
|
2021-06-14 22:25:13 +08:00
|
|
|
BeginFunctionByValue b{};
|
|
|
|
const BeginFunctionByValue bb{};
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::begin(b) == &globalBuff[1]);
|
|
|
|
assert(std::ranges::cbegin(b) == &globalBuff[1]);
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::begin(bb) == &globalBuff[1]);
|
2021-06-14 22:25:13 +08:00
|
|
|
assert(std::ranges::cbegin(bb) == &globalBuff[1]);
|
2021-04-11 13:08:32 +08:00
|
|
|
|
2021-06-14 22:25:13 +08:00
|
|
|
BeginFunctionEnabledBorrowing c{};
|
|
|
|
const BeginFunctionEnabledBorrowing cc{};
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::begin(std::move(c)) == &globalBuff[2]);
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]);
|
2021-06-14 22:25:13 +08:00
|
|
|
assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]);
|
|
|
|
assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]);
|
|
|
|
|
|
|
|
BeginFunctionReturnsEmptyPtr d{};
|
|
|
|
const BeginFunctionReturnsEmptyPtr dd{};
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(!std::invocable<RangeBeginT, decltype((d))>);
|
2021-06-14 22:25:13 +08:00
|
|
|
assert(std::ranges::cbegin(d) == &d.x);
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::begin(dd) == &dd.x);
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::cbegin(dd) == &dd.x);
|
|
|
|
|
2021-06-14 22:25:13 +08:00
|
|
|
BeginFunctionWithDataMember e{};
|
|
|
|
const BeginFunctionWithDataMember ee{};
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(!std::invocable<RangeBeginT, decltype((e))>);
|
2021-06-14 22:25:13 +08:00
|
|
|
assert(std::ranges::begin(ee) == &ee.x);
|
|
|
|
assert(std::ranges::cbegin(e) == &e.x);
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::cbegin(ee) == &ee.x);
|
|
|
|
|
2021-06-14 22:25:13 +08:00
|
|
|
BeginFunctionWithPrivateBeginMember f{};
|
|
|
|
const BeginFunctionWithPrivateBeginMember ff{};
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(!std::invocable<RangeBeginT, decltype((f))>);
|
2021-06-14 22:25:13 +08:00
|
|
|
assert(std::ranges::cbegin(f) == &f.y);
|
2021-12-23 11:36:42 +08:00
|
|
|
assert(std::ranges::begin(ff) == &ff.y);
|
2021-04-11 13:08:32 +08:00
|
|
|
assert(std::ranges::cbegin(ff) == &ff.y);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-14 22:25:13 +08:00
|
|
|
|
|
|
|
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
|
|
|
|
ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<int (&)[10]>()));
|
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
struct NoThrowMemberBegin {
|
2021-12-14 08:21:38 +08:00
|
|
|
ThrowingIterator<int> begin() const noexcept; // auto(t.begin()) doesn't throw
|
|
|
|
} ntmb;
|
|
|
|
static_assert(noexcept(std::ranges::begin(ntmb)));
|
|
|
|
static_assert(noexcept(std::ranges::cbegin(ntmb)));
|
2021-04-11 13:08:32 +08:00
|
|
|
|
|
|
|
struct NoThrowADLBegin {
|
2021-12-14 08:21:38 +08:00
|
|
|
friend ThrowingIterator<int> begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw
|
|
|
|
friend ThrowingIterator<int> begin(const NoThrowADLBegin&) noexcept;
|
|
|
|
} ntab;
|
|
|
|
static_assert(noexcept(std::ranges::begin(ntab)));
|
|
|
|
static_assert(noexcept(std::ranges::cbegin(ntab)));
|
|
|
|
|
|
|
|
struct NoThrowMemberBeginReturnsRef {
|
|
|
|
ThrowingIterator<int>& begin() const noexcept; // auto(t.begin()) may throw
|
|
|
|
} ntmbrr;
|
|
|
|
static_assert(!noexcept(std::ranges::begin(ntmbrr)));
|
|
|
|
static_assert(!noexcept(std::ranges::cbegin(ntmbrr)));
|
2021-04-11 13:08:32 +08:00
|
|
|
|
2021-12-14 03:50:37 +08:00
|
|
|
struct BeginReturnsArrayRef {
|
|
|
|
auto begin() const noexcept -> int(&)[10];
|
|
|
|
} brar;
|
|
|
|
static_assert(noexcept(std::ranges::begin(brar)));
|
|
|
|
static_assert(noexcept(std::ranges::cbegin(brar)));
|
|
|
|
|
2021-12-24 05:53:48 +08:00
|
|
|
// Test ADL-proofing.
|
|
|
|
struct Incomplete;
|
|
|
|
template<class T> struct Holder { T t; };
|
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*>);
|
2022-01-12 03:58:32 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*&>);
|
2021-12-24 05:53:48 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
|
2022-01-12 03:58:32 +08:00
|
|
|
static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
|
2021-12-24 05:53:48 +08:00
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
int main(int, char**) {
|
2021-12-23 11:36:42 +08:00
|
|
|
static_assert(testReturnTypes());
|
|
|
|
|
2021-04-11 13:08:32 +08:00
|
|
|
testArray();
|
|
|
|
static_assert(testArray());
|
|
|
|
|
|
|
|
testBeginMember();
|
|
|
|
static_assert(testBeginMember());
|
|
|
|
|
|
|
|
testBeginFunction();
|
|
|
|
static_assert(testBeginFunction());
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|