diff --git a/docs/matchers.md b/docs/matchers.md index a013245c..a27bbddd 100644 --- a/docs/matchers.md +++ b/docs/matchers.md @@ -491,6 +491,15 @@ TEST_CASE("Constexpr support for matchers", "[constexpr][matchers]") { } ``` +### First party constexpr matchers + +Some (but not all) of Catch2's generic matchers support `constexpr` +matching. Currently, this includes: + +* `IsEmpty()` +* `SizeIs(size_t target_size)` +* `SizeIs(Matcher size_matcher)` + --- diff --git a/src/catch2/matchers/catch_matchers_container_properties.cpp b/src/catch2/matchers/catch_matchers_container_properties.cpp index f0c535bc..6297221e 100644 --- a/src/catch2/matchers/catch_matchers_container_properties.cpp +++ b/src/catch2/matchers/catch_matchers_container_properties.cpp @@ -22,13 +22,5 @@ namespace Matchers { return sstr.str(); } - IsEmptyMatcher IsEmpty() { - return {}; - } - - HasSizeMatcher SizeIs(std::size_t sz) { - return HasSizeMatcher{ sz }; - } - } // end namespace Matchers } // end namespace Catch diff --git a/src/catch2/matchers/catch_matchers_container_properties.hpp b/src/catch2/matchers/catch_matchers_container_properties.hpp index 33795fbe..552bbab1 100644 --- a/src/catch2/matchers/catch_matchers_container_properties.hpp +++ b/src/catch2/matchers/catch_matchers_container_properties.hpp @@ -18,7 +18,7 @@ namespace Catch { class IsEmptyMatcher final : public MatcherGenericBase { public: template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) using Catch::Detail::empty; #else @@ -33,12 +33,12 @@ namespace Catch { class HasSizeMatcher final : public MatcherGenericBase { std::size_t m_target_size; public: - explicit HasSizeMatcher(std::size_t target_size): + constexpr explicit HasSizeMatcher(std::size_t target_size): m_target_size(target_size) {} template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) using Catch::Detail::size; #else @@ -54,12 +54,12 @@ namespace Catch { class SizeMatchesMatcher final : public MatcherGenericBase { Matcher m_matcher; public: - explicit SizeMatchesMatcher(Matcher m): + constexpr explicit SizeMatchesMatcher(Matcher m): m_matcher(CATCH_MOVE(m)) {} template - bool match(RangeLike&& rng) const { + constexpr bool match(RangeLike&& rng) const { #if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS) using Catch::Detail::size; #else @@ -75,11 +75,13 @@ namespace Catch { //! Creates a matcher that accepts empty ranges/containers - IsEmptyMatcher IsEmpty(); + inline CATCH_DESTRUCTOR_CONSTEXPR IsEmptyMatcher IsEmpty() { return {}; } //! Creates a matcher that accepts ranges/containers with specific size - HasSizeMatcher SizeIs(std::size_t sz); + inline CATCH_DESTRUCTOR_CONSTEXPR HasSizeMatcher SizeIs( std::size_t sz ) { + return HasSizeMatcher{ sz }; + } template - std::enable_if_t, + constexpr std::enable_if_t, SizeMatchesMatcher> SizeIs(Matcher&& m) { return SizeMatchesMatcher{CATCH_FORWARD(m)}; } diff --git a/tests/SelfTest/UsageTests/MatchersConstexpr.tests.cpp b/tests/SelfTest/UsageTests/MatchersConstexpr.tests.cpp index edd03519..0d910daf 100644 --- a/tests/SelfTest/UsageTests/MatchersConstexpr.tests.cpp +++ b/tests/SelfTest/UsageTests/MatchersConstexpr.tests.cpp @@ -8,6 +8,9 @@ #include #include +#include + +#include #if defined( CATCH_INTERNAL_CONSTEXPR_MATCHERS_ENABLED ) @@ -34,6 +37,15 @@ TEST_CASE( "Constexpr support for matchers", "[constexpr][matchers][approvals]" STATIC_REQUIRE_THAT( 1, MatchAll() ); } +TEST_CASE( "IsEmpty and HasSize matchers can be used in constexpr contexts", + "[constexpr][matchers][approvals]" ){ + static constexpr std::array empty{}; + STATIC_REQUIRE_THAT( empty, Catch::Matchers::IsEmpty() ); + static constexpr int arr[1] = { 2 }; + STATIC_REQUIRE_THAT( arr, Catch::Matchers::SizeIs( 1 ) ); + STATIC_REQUIRE_THAT( arr, Catch::Matchers::SizeIs( MatchAll() ) ); +} + // Combining matchers needs C++26 and P2738, so they are in separate preprocessor block # if __cpp_constexpr >= 202306L