diff --git a/universal/include/userver/utils/enumerate.hpp b/universal/include/userver/utils/enumerate.hpp index 9547e2e08e3b..45a293c9b5e8 100644 --- a/universal/include/userver/utils/enumerate.hpp +++ b/universal/include/userver/utils/enumerate.hpp @@ -49,26 +49,22 @@ struct IteratorWrapper { } }; -template -using IteratorTypeOf = decltype(std::begin(std::declval())); - -template -using SentinelTypeOf = decltype(std::end(std::declval())); - template struct ContainerWrapper { - constexpr IteratorWrapper> begin() { - return {.iterator = std::begin(container), .pos = 0}; + constexpr auto begin() { + return IteratorWrapper{.iterator = std::begin(container), .pos = 0}; } - constexpr IteratorWrapper> end() { return {.iterator = std::end(container), .pos = 0}; } + constexpr auto end() { + return IteratorWrapper{.iterator = std::end(container), .pos = 0}; + } - constexpr IteratorWrapper> begin() const { - return {.iterator = std::begin(container), .pos = 0}; + constexpr auto begin() const { + return IteratorWrapper{.iterator = std::begin(std::as_const(container)), .pos = 0}; } - constexpr IteratorWrapper> end() const { - return {.iterator = std::end(container), .pos = 0}; + constexpr auto end() const { + return IteratorWrapper{.iterator = std::end(std::as_const(container)), .pos = 0}; } Container container; @@ -81,9 +77,9 @@ namespace utils { /// @brief Implementation of python-style enumerate function for range-for loops /// @param iterable: Container to iterate /// @returns ContainerWrapper, which iterator after dereference returns pair -/// of index and (!!!)non-const reference to element(it seems impossible to make -/// this reference const). It can be used in "range based for loop" with -/// "structured binding" like this +/// of index and reference to element. The reference is const-qualified if either +/// the wrapper itself or the underlying container is const; otherwise, it is non-const. +/// It can be used in "range based for loop" with "structured binding" like this /// @code /// for (auto [pos, elem] : enumerate(someContainer)) {...} /// @endcode diff --git a/universal/src/utils/enumerate_test.cpp b/universal/src/utils/enumerate_test.cpp index 23b204451cfb..f453b42a3d27 100644 --- a/universal/src/utils/enumerate_test.cpp +++ b/universal/src/utils/enumerate_test.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -9,6 +11,31 @@ USERVER_NAMESPACE_BEGIN namespace { +template +using EnumerateImpl = decltype(utils::enumerate(std::declval())); + +template +using Enumerate = std::conditional_t, EnumerateImpl>; + +template +using EnumerateElem = decltype(*std::begin(std::declval&>()))::second_type; + +static_assert(std::is_same_v, false>>); +static_assert(std::is_same_v&, false>>); +static_assert(std::is_same_v&&, false>>); + +static_assert(std::is_same_v, false>>); +static_assert(std::is_same_v&, false>>); +static_assert(std::is_same_v&&, false>>); + +static_assert(std::is_same_v, true>>); +static_assert(std::is_same_v&, true>>); +static_assert(std::is_same_v&&, true>>); + +static_assert(std::is_same_v, true>>); +static_assert(std::is_same_v&, true>>); +static_assert(std::is_same_v&&, true>>); + constexpr int ConstexprTest(std::array data) { int result = 0; for (auto [pos, elem] : utils::enumerate(data)) {