Skip to content

[libc++][iterator][ranges] P2997R1: Removing the common reference requirement from the indirectly invocable concepts #98817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Implemented Papers
- P3142R0 - Printing Blank Lines with ``println`` (as DR against C++23)
- P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only)
- P2968R2 - Make ``std::ignore`` a first-class object
- P2997R1 - Removing the common reference requirement from the indirectly invocable concepts (as DR against C++20)
- P2302R4 - ``std::ranges::contains``
- P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
- P3029R1 - Better ``mdspan``'s CTAD
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/Status/Cxx2c.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Paper Status
.. [#note-P3142R0] This paper is applied as DR against C++23. (MSVC STL and libstdc++ will do the same.)
.. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only.
.. [#note-P2422R1] Libc++ keeps the ``nodiscard`` attributes as a conforming extension.
.. [#note-P2997R1] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
.. _issues-status-cxx2c:

Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0",""
"","","","","","",""
"`P2747R2 <https://wg21.link/P2747R2>`__","CWG","``constexpr`` placement new","St. Louis June 2024","","",""
"`P2997R1 <https://wg21.link/P2997R1>`__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","","",""
"`P2997R1 <https://wg21.link/P2997R1>`__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","|Complete| [#note-P2997R1]_","19.0",""
"`P2389R2 <https://wg21.link/P2389R2>`__","LWG","``dextents`` Index Type Parameter","St. Louis June 2024","|Complete|","19.0",""
"`P3168R2 <https://wg21.link/P3168R2>`__","LWG","Give ``std::optional`` Range Support","St. Louis June 2024","","","|ranges|"
"`P3217R0 <https://wg21.link/P3217R0>`__","LWG","Adjoints to 'Enabling list-initialization for algorithms': find_last","St. Louis June 2024","","",""
Expand Down
15 changes: 6 additions & 9 deletions libcxx/include/__iterator/concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,46 +177,43 @@ concept __has_arrow = input_iterator<_Ip> && (is_pointer_v<_Ip> || requires(_Ip
template <class _Fp, class _It>
concept indirectly_unary_invocable =
indirectly_readable<_It> && copy_constructible<_Fp> && invocable<_Fp&, iter_value_t<_It>&> &&
invocable<_Fp&, iter_reference_t<_It>> && invocable<_Fp&, iter_common_reference_t<_It>> &&
invocable<_Fp&, iter_reference_t<_It>> &&
common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>;

template <class _Fp, class _It>
concept indirectly_regular_unary_invocable =
indirectly_readable<_It> && copy_constructible<_Fp> && regular_invocable<_Fp&, iter_value_t<_It>&> &&
regular_invocable<_Fp&, iter_reference_t<_It>> && regular_invocable<_Fp&, iter_common_reference_t<_It>> &&
regular_invocable<_Fp&, iter_reference_t<_It>> &&
common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>;

template <class _Fp, class _It>
concept indirect_unary_predicate =
indirectly_readable<_It> && copy_constructible<_Fp> && predicate<_Fp&, iter_value_t<_It>&> &&
predicate<_Fp&, iter_reference_t<_It>> && predicate<_Fp&, iter_common_reference_t<_It>>;
predicate<_Fp&, iter_reference_t<_It>>;

template <class _Fp, class _It1, class _It2>
concept indirect_binary_predicate =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
predicate<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;

template <class _Fp, class _It1, class _It2 = _It1>
concept indirect_equivalence_relation =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
equivalence_relation<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;

template <class _Fp, class _It1, class _It2 = _It1>
concept indirect_strict_weak_order =
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
strict_weak_order<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;

template <class _Fp, class... _Its>
requires(indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ struct BadPredicate5 {
};
static_assert(!std::indirect_binary_predicate<BadPredicate5, It1, It2>);

// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t)
struct BadPredicate6 {
template <class T, class U> bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
// This case was made valid by P2997R1.
struct GoodPredicate6 {
template <class T, class U>
bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>);
static_assert(std::indirect_binary_predicate<GoodPredicate6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ struct BadRelation5 {
};
static_assert(!std::indirect_equivalence_relation<BadRelation5, It1, It2>);

// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
struct BadRelation6 {
template <class T, class U> bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
// This case was made valid by P2997R1.
struct GoodRelation6 {
template <class T, class U>
bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>);
static_assert(std::indirect_equivalence_relation<GoodRelation6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ struct BadOrder5 {
};
static_assert(!std::indirect_strict_weak_order<BadOrder5, It1, It2>);

// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
struct BadOrder6 {
template <class T, class U> bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
// This case was made valid by P2997R1.
struct GoodOrder6 {
template <class T, class U>
bool operator()(T const&, U const&) const;
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_strict_weak_order<BadOrder6, It1, It2>);
static_assert(std::indirect_strict_weak_order<GoodOrder6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ struct BadPredicate3 {
};
static_assert(!std::indirect_unary_predicate<BadPredicate3, It>);

// Should fail when the predicate can't be called with std::iter_common_reference_t<It>
struct BadPredicate4 {
template <class T> bool operator()(T const&) const;
bool operator()(std::iter_common_reference_t<It>) const = delete;
// This case was made valid by P2997R1.
struct GoodPredicate4 {
template <class T>
bool operator()(T const&) const;
bool operator()(std::iter_common_reference_t<It>) const = delete;
};
static_assert(!std::indirect_unary_predicate<BadPredicate4, It>);
static_assert(std::indirect_unary_predicate<GoodPredicate4, It>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ struct BadInvocable3 {
};
static_assert(!std::indirectly_regular_unary_invocable<BadInvocable3, It>);

// Should fail when the invocable can't be called with (iter_common_reference_t)
struct BadInvocable4 {
template <class T> R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
// This case was made valid by P2997R1.
struct GoodInvocable4 {
template <class T>
R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
};
static_assert(!std::indirectly_regular_unary_invocable<BadInvocable4, It>);
static_assert(std::indirectly_regular_unary_invocable<GoodInvocable4, It>);

// Should fail when the invocable doesn't have a common reference between its return types
struct BadInvocable5 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ struct BadInvocable3 {
};
static_assert(!std::indirectly_unary_invocable<BadInvocable3, It>);

// Should fail when the invocable can't be called with (iter_common_reference_t)
struct BadInvocable4 {
template <class T> R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
// This case was made valid by P2997R1.
struct GoodInvocable4 {
template <class T>
R1 operator()(T const&) const;
R1 operator()(std::iter_common_reference_t<It>) const = delete;
};
static_assert(!std::indirectly_unary_invocable<BadInvocable4, It>);
static_assert(std::indirectly_unary_invocable<GoodInvocable4, It>);

// Should fail when the invocable doesn't have a common reference between its return types
struct BadInvocable5 {
Expand Down
3 changes: 2 additions & 1 deletion libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,8 @@ def add_version_header(tc):
"name": "__cpp_lib_ranges",
"values": {
"c++20": 202207,
# "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts
# "c++23": 202302, # Relaxing Ranges Just A Smidge
# "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (already implemented as a DR)
},
"headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
},
Expand Down