diff --git a/include/stdx/call_by_need.hpp b/include/stdx/call_by_need.hpp index e4355cc..6be294f 100644 --- a/include/stdx/call_by_need.hpp +++ b/include/stdx/call_by_need.hpp @@ -46,23 +46,31 @@ struct void_t {}; template using is_nonvoid_t = std::bool_constant>; -template +template +using invoke_result_t = + decltype(CallPolicy::invoke(std::declval(), std::declval()...)); + +template constexpr auto invoke(F &&f, Args &&args) -> decltype(auto) { - return [&]( - std::index_sequence) -> decltype(auto) { - using R = std::invoke_result_t( - std::forward(args)))...>; - if constexpr (std::is_void_v) { - std::forward(f)(get(std::forward(args))...); - return void_t{}; - } else { - return std::forward(f)( - get(std::forward(args))...); - } - }(std::make_index_sequence{}); + return + [&](std::index_sequence) -> decltype(auto) { + using R = invoke_result_t( + std::forward(args)))...>; + if constexpr (std::is_void_v) { + CallPolicy::invoke(std::forward(f), + get(std::forward(args))...); + return void_t{}; + } else { + return CallPolicy::invoke( + std::forward(f), + get(std::forward(args))...); + } + }(std::make_index_sequence{}); } -template struct by_need { +template struct by_need { template [[nodiscard]] consteval static auto compute_call_info_impl() { auto results = std::array{}; @@ -72,8 +80,8 @@ template struct by_need { [&]() -> bool { return [&](std::index_sequence) -> bool { if constexpr (requires { - typename std::invoke_result_t< - nth_t, + typename invoke_result_t< + CallPolicy, nth_t, nth_t...>; }) { results[result_count++] = {N, Base, Len}; @@ -145,15 +153,24 @@ template struct by_need { struct safe_forward { template constexpr auto operator()(T &&t) -> T { return t; } }; + +struct default_call_policy_t { + template + constexpr static auto invoke(F &&f, Args &&...args) + -> std::invoke_result_t { + return std::forward(f)(std::forward(args)...); + } +}; } // namespace cbn_detail -template +template constexpr auto call_by_need(Fs &&fs, Args &&args) { constexpr auto calls = [&](std::index_sequence, std::index_sequence) { - return cbn_detail::by_need( - std::forward(fs)))...>:: + return cbn_detail::by_need< + CallPolicy, decltype(get(std::forward(fs)))...>:: template compute_call_info( std::forward(args)))...>(); }(std::make_index_sequence>>{}, @@ -165,11 +182,12 @@ constexpr auto call_by_need(Fs &&fs, Args &&args) { }(std::make_index_sequence>{}); auto ret = [&](std::index_sequence) { - return tuple< - decltype(cbn_detail::invoke( - get(std::move(new_fs)), - std::forward(args)))...>{ - cbn_detail::invoke( + return tuple( + get(std::move(new_fs)), + std::forward(args)))...>{ + cbn_detail::invoke( get(std::move(new_fs)), std::forward(args))...}; }(std::make_index_sequence{}); diff --git a/test/call_by_need.cpp b/test/call_by_need.cpp index ac44a7b..84dbaf9 100644 --- a/test/call_by_need.cpp +++ b/test/call_by_need.cpp @@ -214,3 +214,26 @@ TEST_CASE("function returning reference", "[call_by_need]") { STATIC_REQUIRE(std::is_same_v const>); CHECK(get<0>(r) == 17); } + +namespace { +template struct custom_call_policy_t { + template + constexpr static auto invoke(F &&f, Args &&...args) + -> decltype(std::forward(f).template operator()( + std::forward(args)...)) { + return std::forward(f).template operator()( + std::forward(args)...); + } +}; +} // namespace + +TEST_CASE("custom call policy", "[call_by_need]") { + auto r = stdx::call_by_need>( + stdx::tuple{[&](arg_t<0>) { + STATIC_CHECK(std::same_as); + return 17; + }}, + stdx::tuple{arg<0>}); + STATIC_REQUIRE(std::is_same_v>); + CHECK(get<0>(r) == 17); +}