diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -18,7 +18,12 @@ namespace std { template struct incrementable_traits; // since C++20 +template + using iter_difference_t = see below; // since C++20 + template struct indirectly_readable_traits; // since C++20 +template + using iter_value_t = see below; // since C++20 template struct iterator_traits @@ -437,6 +442,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct _LIBCPP_TEMPLATE_VIS iterator_traits; + #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) // [incrementable.traits] template struct incrementable_traits {}; @@ -470,7 +478,27 @@ using difference_type = make_signed_t() - declval<_Tp>())>; }; -// TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up. +// Let `R[I]` be `remove_­cvref_­t`. The type `iter_­difference_­t` denotes +template +struct __extract_iter_difference_t; + +template +using iter_difference_t = typename __extract_iter_difference_t>::type; + +// `incrementable_­traits::difference_­type` if `iterator_­traits` names a specialization +// generated from the primary template, and +template +requires __is_primary_template>::value && + (__has_member_difference_type<_Ip> || __has_integral_minus<_Ip>) +struct __extract_iter_difference_t<_Ip> { + using type = typename incrementable_traits<_Ip>::difference_type; +}; + +// `iterator_­traits::difference_­type` otherwise. +template +struct __extract_iter_difference_t { + using type = typename iterator_traits<_Ip>::difference_type; +}; // [readable.traits] template struct indirectly_readable_traits {}; @@ -518,7 +546,27 @@ struct indirectly_readable_traits<_Tp> : __cond_value_type {}; -// TODO(cjdb): add iter_value_t once iterator_traits is cleaned up. +// Let `R[I]` be `remove_­cvref_­t`. The type `iter_­value_­t` denotes +template +struct __extract_iter_value_t; + +template +using iter_value_t = typename __extract_iter_value_t>::type; + +// indirectly_­readable_­traits::value_­type if `iterator_­traits` names a specialization +// generated from the primary template, and +template +requires __is_primary_template>::value && + __has_member_value_type> +struct __extract_iter_value_t<_Ip> { + using type = typename indirectly_readable_traits<_Ip>::value_type; +}; + +// iterator_­traits::value_­type otherwise. +template +struct __extract_iter_value_t { + using type = typename iterator_traits<_Ip>::value_type; +}; template using __with_reference = _Tp&; @@ -537,9 +585,6 @@ using iter_reference_t = decltype(*declval<_Tp&>()); #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) -template -struct _LIBCPP_TEMPLATE_VIS iterator_traits; - struct _LIBCPP_TEMPLATE_VIS input_iterator_tag {}; struct _LIBCPP_TEMPLATE_VIS output_iterator_tag {}; struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag : public input_iterator_tag {}; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.fail.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.fail.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template +// using iter_difference_t; + +#include + +using fails1 = std::iter_difference_t; +// expected-error@iterator:* {{no type named 'difference_type' in 'std::iterator_traits'}} + +using fails2 = std::iter_difference_t; +// expected-error@iterator:* {{no type named 'difference_type' in 'std::iterator_traits'}} + +struct S {}; +using fails3 = std::iter_difference_t; +// expected-error@iterator:* {{no type named 'difference_type' in 'std::iterator_traits'}} + +struct void_subtraction { + friend void operator-(void_subtraction, void_subtraction); +}; +using fails4 = std::iter_difference_t; +// expected-error@iterator:* {{no type named 'difference_type' in 'std::iterator_traits'}} + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/iter_difference_t.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template +// using iter_difference_t; + +#include + +#include +#include + +template +[[nodiscard]] constexpr bool check_iter_difference_t() { + constexpr bool result = std::same_as, Expected>; + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert( + std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert( + std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert( + std::same_as, Expected> == + result); + + return result; +} + +static_assert(check_iter_difference_t()); +static_assert(check_iter_difference_t()); +static_assert( + check_iter_difference_t::iterator, + std::vector::iterator::difference_type>()); + +struct int_subtraction { + friend int operator-(int_subtraction, int_subtraction) noexcept; +}; +static_assert(check_iter_difference_t()); + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.fail.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.fail.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template +// using iter_value_t; + +#include + +using fail1 = std::iter_value_t; +// expected-error@iterator:* {{no type named 'value_type' in 'std::iterator_traits'}} + +using fail2 = std::iter_value_t; +// expected-error@iterator:* {{no type named 'value_type' in 'std::iterator_traits'}} + +struct S {}; +using fail3 = std::iter_value_t; +// expected-error@iterator:* {{no type named 'value_type' in 'std::iterator_traits'}} + +struct different_value_element { + using value_type = int; + using element_type = long; +}; +using fail4 = std::iter_value_t; +// expected-error@iterator:* {{no type named 'value_type' in 'std::iterator_traits'}} + +int main(int, char**) { return 0; } diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/readable.traits/iter_value_t.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template +// using iter_value_t; + +#include + +#include +#include +#include + +template +[[nodiscard]] constexpr bool check_iter_value_t() { + constexpr bool result = std::same_as, Expected>; + static_assert(std::same_as, Expected> == result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == result); + static_assert(std::same_as, Expected> == + result); + static_assert(std::same_as, Expected> == + result); + + return result; +} + +static_assert(check_iter_value_t()); +static_assert(check_iter_value_t()); +static_assert(check_iter_value_t()); +static_assert(check_iter_value_t::iterator, + std::vector::iterator::value_type>()); +static_assert(check_iter_value_t, + std::shared_ptr::element_type>()); + +struct both_members { + using value_type = double; + using element_type = double; +}; +static_assert(check_iter_value_t()); + +int main(int, char**) { return 0; }