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,14 @@ 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 +// `incrementable_­traits::difference_­type` if `iterator_­traits` names a specialization +// generated from the primary template, and `iterator_­traits::difference_­type` otherwise. +template +using iter_difference_t = typename conditional_t< + __is_primary_template>>::value, + incrementable_traits>, + iterator_traits>>::difference_type; // [readable.traits] template struct indirectly_readable_traits {}; @@ -518,7 +533,14 @@ 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 +// `indirectly_­readable_­traits::value_­type` if `iterator_­traits` names a specialization +// `iterator_­traits::value_­type` otherwise. generated from the primary template, and +template +using iter_value_t = typename conditional_t< + __is_primary_template>>::value, + indirectly_readable_traits>, + iterator_traits>>::value_type; template using __with_reference = _Tp&; @@ -537,9 +559,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.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,84 @@ +//===----------------------------------------------------------------------===// +// +// 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()); + +// clang-format off +template +requires requires { typename std::iter_difference_t; } +[[nodiscard]] constexpr bool check_no_iter_difference_t() { + return false; +} +// clang-format on + +template +[[nodiscard]] constexpr bool check_no_iter_difference_t() { + return true; +} + +static_assert(check_no_iter_difference_t()); +static_assert(check_no_iter_difference_t()); + +struct S {}; +static_assert(check_no_iter_difference_t()); + +struct void_subtraction { + friend void operator-(void_subtraction, void_subtraction); +}; +static_assert(check_no_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.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,83 @@ +//===----------------------------------------------------------------------===// +// +// 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()); + +// clang-format off +template +requires requires { typename std::iter_value_t; } +[[nodiscard]] constexpr bool check_no_iter_value_t() { + return false; +} +// clang-format on + +template +[[nodiscard]] constexpr bool check_no_iter_value_t() { + return true; +} + +static_assert(check_no_iter_value_t()); +static_assert(check_no_iter_value_t()); + +struct S {}; +static_assert(check_no_iter_value_t()); + +struct different_value_element_members { + using value_type = int; + using element_type = long; +}; +static_assert(check_no_iter_value_t()); + +int main(int, char**) { return 0; }