From 074a32af66648c74dd0104e251e44ace5b59f7fa Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 3 Jul 2024 22:07:51 -0700 Subject: Mark c_min_element, c_max_element, and c_minmax_element as constexpr in C++17. This allows them to be used in constant expressions, such as static_asserts. PiperOrigin-RevId: 649292841 Change-Id: I76e31a94b933fa357276fee534b81c00c28c8b23 --- absl/algorithm/container.h | 36 +++++++++++++++++++++--------------- absl/algorithm/container_test.cc | 36 ++++++++++++++++++++++++++++++++++++ absl/base/config.h | 24 ++++++++++++------------ 3 files changed, 69 insertions(+), 27 deletions(-) (limited to 'absl') diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index 352ac46c..6bbe3b5a 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h @@ -99,12 +99,12 @@ using ContainerPointerType = // These are meant for internal use only. template -ABSL_CONSTEXPR_SINCE_CXX17 ContainerIter c_begin(C& c) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 ContainerIter c_begin(C& c) { return begin(c); } template -ABSL_CONSTEXPR_SINCE_CXX17 ContainerIter c_end(C& c) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 ContainerIter c_end(C& c) { return end(c); } @@ -147,7 +147,7 @@ bool c_linear_search(const C& c, EqualityComparable&& value) { // Container-based version of the `std::distance()` function to // return the number of elements within a container. template -ABSL_CONSTEXPR_SINCE_CXX17 +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 container_algorithm_internal::ContainerDifferenceType c_distance(const C& c) { return std::distance(container_algorithm_internal::c_begin(c), @@ -1533,8 +1533,9 @@ c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) { // to return an iterator pointing to the element with the smallest value, using // `operator<` to make the comparisons. template -container_algorithm_internal::ContainerIter c_min_element( - Sequence& sequence) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 + container_algorithm_internal::ContainerIter + c_min_element(Sequence& sequence) { return std::min_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence)); } @@ -1542,8 +1543,9 @@ container_algorithm_internal::ContainerIter c_min_element( // Overload of c_min_element() for performing a `comp` comparison other than // `operator<`. template -container_algorithm_internal::ContainerIter c_min_element( - Sequence& sequence, LessThan&& comp) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 + container_algorithm_internal::ContainerIter + c_min_element(Sequence& sequence, LessThan&& comp) { return std::min_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), std::forward(comp)); @@ -1555,8 +1557,9 @@ container_algorithm_internal::ContainerIter c_min_element( // to return an iterator pointing to the element with the largest value, using // `operator<` to make the comparisons. template -container_algorithm_internal::ContainerIter c_max_element( - Sequence& sequence) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 + container_algorithm_internal::ContainerIter + c_max_element(Sequence& sequence) { return std::max_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence)); } @@ -1564,8 +1567,9 @@ container_algorithm_internal::ContainerIter c_max_element( // Overload of c_max_element() for performing a `comp` comparison other than // `operator<`. template -container_algorithm_internal::ContainerIter c_max_element( - Sequence& sequence, LessThan&& comp) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 + container_algorithm_internal::ContainerIter + c_max_element(Sequence& sequence, LessThan&& comp) { return std::max_element(container_algorithm_internal::c_begin(sequence), container_algorithm_internal::c_end(sequence), std::forward(comp)); @@ -1578,8 +1582,9 @@ container_algorithm_internal::ContainerIter c_max_element( // smallest and largest values, respectively, using `operator<` to make the // comparisons. template -container_algorithm_internal::ContainerIterPairType c_minmax_element( - C& c) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 + container_algorithm_internal::ContainerIterPairType + c_minmax_element(C& c) { return std::minmax_element(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c)); } @@ -1587,8 +1592,9 @@ container_algorithm_internal::ContainerIterPairType c_minmax_element( // Overload of c_minmax_element() for performing `comp` comparisons other than // `operator<`. template -container_algorithm_internal::ContainerIterPairType c_minmax_element( - C& c, LessThan&& comp) { +ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 + container_algorithm_internal::ContainerIterPairType + c_minmax_element(C& c, LessThan&& comp) { return std::minmax_element(container_algorithm_internal::c_begin(c), container_algorithm_internal::c_end(c), std::forward(comp)); diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc index e5e2bf3d..50122249 100644 --- a/absl/algorithm/container_test.cc +++ b/absl/algorithm/container_test.cc @@ -1168,6 +1168,42 @@ TEST(ConstexprTest, Distance) { // Works at compile time with constexpr containers. static_assert(absl::c_distance(std::array()) == 3); } + +TEST(ConstexprTest, MinElement) { + constexpr std::array kArray = {1, 2, 3}; + static_assert(*absl::c_min_element(kArray) == 1); +} + +TEST(ConstexprTest, MinElementWithPredicate) { + constexpr std::array kArray = {1, 2, 3}; + static_assert(*absl::c_min_element(kArray, std::greater()) == 3); +} + +TEST(ConstexprTest, MaxElement) { + constexpr std::array kArray = {1, 2, 3}; + static_assert(*absl::c_max_element(kArray) == 3); +} + +TEST(ConstexprTest, MaxElementWithPredicate) { + constexpr std::array kArray = {1, 2, 3}; + static_assert(*absl::c_max_element(kArray, std::greater()) == 1); +} + +TEST(ConstexprTest, MinMaxElement) { + static constexpr std::array kArray = {1, 2, 3}; + constexpr auto kMinMaxPair = absl::c_minmax_element(kArray); + static_assert(*kMinMaxPair.first == 1); + static_assert(*kMinMaxPair.second == 3); +} + +TEST(ConstexprTest, MinMaxElementWithPredicate) { + static constexpr std::array kArray = {1, 2, 3}; + constexpr auto kMinMaxPair = + absl::c_minmax_element(kArray, std::greater()); + static_assert(*kMinMaxPair.first == 3); + static_assert(*kMinMaxPair.second == 1); +} + #endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L diff --git a/absl/base/config.h b/absl/base/config.h index 13263f9d..97c9a22a 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -941,25 +941,25 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_HAVE_CONSTANT_EVALUATED 1 #endif -// ABSL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr for -// different C++ versions. -#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ - ABSL_INTERNAL_CPLUSPLUS_LANG >= 201402L -#define ABSL_CONSTEXPR_SINCE_CXX14 constexpr -#else -#define ABSL_CONSTEXPR_SINCE_CXX14 -#endif +// ABSL_INTERNAL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr +// for different C++ versions. +// +// These macros are an implementation detail and will be unconditionally removed +// once the minimum supported C++ version catches up to a given version. +// +// For this reason, this symbol is considered INTERNAL and code outside of +// Abseil must not use it. #if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L -#define ABSL_CONSTEXPR_SINCE_CXX17 constexpr +#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 constexpr #else -#define ABSL_CONSTEXPR_SINCE_CXX17 +#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 #endif #if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \ ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L -#define ABSL_CONSTEXPR_SINCE_CXX20 constexpr +#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 constexpr #else -#define ABSL_CONSTEXPR_SINCE_CXX20 +#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 #endif // ABSL_INTERNAL_EMSCRIPTEN_VERSION combines Emscripten's three version macros -- cgit v1.2.3