aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2023-06-23 12:18:11 +0100
committerJonathan Wakely <jwakely@redhat.com>2023-06-26 17:43:22 +0100
commit6eafdfc73c21d7a5e59e18c9dee275af5bf6d979 (patch)
tree5bb575f5e95bd5be4da9309de4dd07d4d5d8cdd5
parentfa98bc4270dcb4ec78b5b1c0f4c067094c84bae6 (diff)
downloadgcc-6eafdfc73c21d7a5e59e18c9dee275af5bf6d979.zip
gcc-6eafdfc73c21d7a5e59e18c9dee275af5bf6d979.tar.gz
gcc-6eafdfc73c21d7a5e59e18c9dee275af5bf6d979.tar.bz2
libstdc++: Implement P2538R1 ADL-proof std::projected
This was recently approved for C++26, but there's no harm in implementing it unconditionally for C++20 and C++23. As it says in the paper, it doesn't change the meaning of any valid code. It only enables things that were previously ill-formed for questionable reasons. libstdc++-v3/ChangeLog: * include/bits/iterator_concepts.h (projected): Replace class template with alias template denoting an ADL-proofed helper. (incremental_traits<projected<Iter, Proj>>): Remove. * testsuite/24_iterators/indirect_callable/projected-adl.cc: New test.
-rw-r--r--libstdc++-v3/include/bits/iterator_concepts.h35
-rw-r--r--libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc42
2 files changed, 67 insertions, 10 deletions
diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h
index 1555c37..6802582 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -771,19 +771,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& invocable<_Fn, iter_reference_t<_Is>...>
using indirect_result_t = invoke_result_t<_Fn, iter_reference_t<_Is>...>;
+ namespace __detail
+ {
+ template<typename _Iter, typename _Proj>
+ struct __projected
+ {
+ struct __type
+ {
+ using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>;
+ indirect_result_t<_Proj&, _Iter> operator*() const; // not defined
+ };
+ };
+
+ template<weakly_incrementable _Iter, typename _Proj>
+ struct __projected<_Iter, _Proj>
+ {
+ struct __type
+ {
+ using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>;
+ using difference_type = iter_difference_t<_Iter>;
+ indirect_result_t<_Proj&, _Iter> operator*() const; // not defined
+ };
+ };
+ } // namespace __detail
+
/// [projected], projected
template<indirectly_readable _Iter,
indirectly_regular_unary_invocable<_Iter> _Proj>
- struct projected
- {
- using value_type = remove_cvref_t<indirect_result_t<_Proj&, _Iter>>;
-
- indirect_result_t<_Proj&, _Iter> operator*() const; // not defined
- };
-
- template<weakly_incrementable _Iter, typename _Proj>
- struct incrementable_traits<projected<_Iter, _Proj>>
- { using difference_type = iter_difference_t<_Iter>; };
+ using projected = __detail::__projected<_Iter, _Proj>::__type;
// [alg.req], common algorithm requirements
diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc
new file mode 100644
index 0000000..4c2a095
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected-adl.cc
@@ -0,0 +1,42 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+// P2538R1 ADL-proof std::projected
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2538r1.html
+
+#include <iterator>
+
+template<typename T>
+ concept has_diff_type = requires { typename T::difference_type; };
+
+static_assert( has_diff_type<std::projected<int*, void(*)(int)>> );
+
+struct Indy {
+ using value_type = int;
+ int operator*() const { return 0; }
+};
+static_assert( ! std::weakly_incrementable<Indy> );
+static_assert( ! has_diff_type<std::projected<Indy, void(*)(int)>> );
+
+
+// Examples from the paper:
+
+template<class T> struct Holder { T t; };
+struct Incomplete;
+
+void test_concepts()
+{
+ using T = Holder<Incomplete>*;
+ static_assert(std::equality_comparable<T>);
+ (void) std::indirectly_comparable<T*, T*, std::equal_to<>>;
+ (void) std::sortable<T*>;
+}
+
+#include <algorithm>
+
+void test_count()
+{
+ Holder<Incomplete>* a = nullptr;
+ (void) std::count(&a, &a, nullptr);
+ (void) std::ranges::count(&a, &a, nullptr); // { dg-bogus "." }
+}