From c7742dd4a5b6528677b36dae357d62bf5f5d0eb5 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Wed, 13 Aug 2025 13:29:02 -0600 Subject: [PATCH] :bug: Fix constexpr detection Problem: - Variables which are not `constexpr`, but are `static`, are erroneously detected as `constexpr`. Solution: - Fix the `constexpr` detection. --- include/stdx/utility.hpp | 32 +++++++++++++++----------------- test/utility.cpp | 22 +++++++++++++++++++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/include/stdx/utility.hpp b/include/stdx/utility.hpp index 910622e..8783a1c 100644 --- a/include/stdx/utility.hpp +++ b/include/stdx/utility.hpp @@ -277,26 +277,23 @@ template constexpr auto is_ct_v = is_ct_v; }([&]() constexpr { return __VA_ARGS__; }) #endif -#ifndef CX_DETECT -#ifdef __clang__ -#define CX_DETECT(...) \ - std::is_empty_v -#else namespace stdx { inline namespace v1 { -template constexpr auto cx_detect0() {} -constexpr auto cx_detect1(auto) { return 0; } +namespace cxv_detail { +template constexpr auto cx_sfinae = std::true_type{}; + +#ifdef __clang__ +auto cx_detect(auto f) -> decltype(cx_sfinae); +auto cx_detect(...) -> std::false_type; +#else +auto cx_detect(auto f) { + constexpr auto b = requires { cx_sfinae; }; + return std::bool_constant{}; +} +#endif +} // namespace cxv_detail } // namespace v1 } // namespace stdx -#define CX_DETECT(...) \ - requires { \ - ::stdx::cx_detect0<::stdx::cx_detect1( \ - (__VA_ARGS__) + ::stdx::cxv_detail::type_val{})>; \ - } -#endif -#endif #ifndef CX_WRAP #define CX_WRAP(...) \ @@ -310,7 +307,8 @@ constexpr auto cx_detect1(auto) { return 0; } std::is_empty_v< \ std::invoke_result_t>) { \ return f(); \ - } else if constexpr (CX_DETECT(__VA_ARGS__)) { \ + } else if constexpr (decltype(::stdx::cxv_detail::cx_detect( \ + f))::value) { \ return ::stdx::overload{::stdx::cxv_detail::cx_base{}, f}; \ } else { \ return f(); \ diff --git a/test/utility.cpp b/test/utility.cpp index bfbaeb9..adada35 100644 --- a/test/utility.cpp +++ b/test/utility.cpp @@ -317,6 +317,26 @@ TEST_CASE("CX_WRAP string_view runtime arg", "[utility]") { CHECK(CX_WRAP(x) == std::string_view{"hello"}); } +namespace { +auto at_init_time() { return 17; } +auto nc_var = at_init_time(); +} // namespace + +TEST_CASE("CX_WRAP static runtime arg", "[utility]") { + STATIC_REQUIRE(std::is_same_v); + CHECK(CX_WRAP(nc_var) == 17); +} + +namespace { +constexpr auto at_compile_time() { return 17; } +constexpr auto c_var = at_compile_time(); +} // namespace + +TEST_CASE("CX_WRAP static constexpr arg", "[utility]") { + STATIC_REQUIRE(stdx::is_cx_value_v); + STATIC_REQUIRE(CX_WRAP(c_var)() == 17); +} + TEST_CASE("CX_WRAP const integral type", "[utility]") { auto const x = 17; STATIC_REQUIRE(stdx::is_cx_value_v); @@ -378,7 +398,7 @@ TEST_CASE("CX_WRAP integral_constant arg", "[utility]") { #ifdef __clang__ namespace { struct expression_test { - int f(int x) { return x; } + auto f(int x) -> int { return x; } }; } // namespace