diff --git a/include/stdx/env.hpp b/include/stdx/env.hpp index 4dbd423..112a87e 100644 --- a/include/stdx/env.hpp +++ b/include/stdx/env.hpp @@ -93,6 +93,20 @@ using append_env_t = boost::mp11::mp_unique_if< template <_env::autowrap... Args> using make_env_t = extend_env_t, Args...>; + +template constexpr auto query(Q q) -> decltype(auto) { + return q(Env{}); +} + +template +constexpr auto query(Q q, [[maybe_unused]] Default &&d) -> decltype(auto) { + if constexpr (requires { q(Env{}); }) { + return q(Env{}); + } else { + return std::forward(d); + } +} + } // namespace v1 } // namespace stdx diff --git a/test/env.cpp b/test/env.cpp index 87a3de7..d7f166b 100644 --- a/test/env.cpp +++ b/test/env.cpp @@ -18,10 +18,29 @@ namespace { } custom; } // namespace -TEST_CASE("lookup query with default", "[env]") { +TEST_CASE("lookup query with internal default", "[env]") { STATIC_REQUIRE(custom(stdx::env<>{}) == 42); } +TEST_CASE("lookup query with default (free function)", "[env]") { + STATIC_REQUIRE(stdx::query>(custom) == 42); +} + +namespace { +[[maybe_unused]] constexpr inline struct custom_no_default_t { + template + [[nodiscard]] CONSTEVAL auto operator()(T &&t) const + noexcept(noexcept(std::forward(t).query(std::declval()))) + -> decltype(std::forward(t).query(*this)) { + return std::forward(t).query(*this); + } +} custom_no_default; +} // namespace + +TEST_CASE("lookup query with external default", "[env]") { + STATIC_REQUIRE(stdx::query>(custom_no_default, 42) == 42); +} + TEST_CASE("make an environment", "[env]") { using E = stdx::make_env_t; STATIC_REQUIRE(custom(E{}) == 17);