Open1
引数で値を受け渡しする関数を戻り値で返すようにする
初期実装
#include <functional>
#include <print>
#include <tuple>
#include <type_traits>
#include <utility>
namespace yk {
template <class T, template <class...> class TT>
struct is_specialization_of : std::false_type {};
template <template <class...> class TT, class... Ts>
struct is_specialization_of<TT<Ts...>, TT> : std::true_type {};
template <class T, template <class...> class TT>
inline constexpr bool is_specialization_of_v = is_specialization_of<T, TT>::value;
template <template <class...> class TT, class... Ts>
struct count_specializations : std::integral_constant<std::size_t, 0> {};
template <template <class...> class TT, class T, class... Ts>
struct count_specializations<TT, T, Ts...> : std::integral_constant<std::size_t, count_specializations<TT, Ts...>::value + is_specialization_of_v<T, TT>> {};
namespace detail {
template <std::size_t N, template <class...> class TT, class Seq, class... Ts>
struct count_specializations_until_impl {};
template <std::size_t N, template <class...> class TT, std::size_t... Is, class... Ts>
struct count_specializations_until_impl<N, TT, std::index_sequence<Is...>, Ts...> : count_specializations<TT, std::conditional_t<(Is < N), Ts, void>...> {};
} // namespace detail
template <std::size_t N, template <class...> class TT, class... Ts>
struct count_specializations_until : detail::count_specializations_until_impl<N, TT, std::index_sequence_for<Ts...>, Ts...> {};
template <class T, class Tuple>
struct prepend_tuple {};
template <class T, class... Ts>
struct prepend_tuple<T, std::tuple<Ts...>> {
using type = std::tuple<T, Ts...>;
};
template <class T, class Tuple>
using prepend_tuple_t = typename prepend_tuple<T, Tuple>::type;
template <class T>
struct ref_placeholder_t {};
template <class T>
inline constexpr ref_placeholder_t<T> ref;
template <class T, std::size_t I, class... Ts, class Tuple>
constexpr decltype(auto) get_or_forward(T&& x, Tuple&& tuple) {
if constexpr (is_specialization_of_v<std::remove_cvref_t<T>, ref_placeholder_t>) {
return std::get<count_specializations_until<I, ref_placeholder_t, std::remove_cvref_t<Ts>...>::value>(tuple);
} else {
return std::forward<T>(x);
}
}
template <class... Ts>
struct ref_invoke_tuple_helper {};
template <>
struct ref_invoke_tuple_helper<> {
using type = std::tuple<>;
};
template <class T, class... Ts>
struct ref_invoke_tuple_helper<T, Ts...> : ref_invoke_tuple_helper<Ts...> {};
template <class T, class... Ts>
struct ref_invoke_tuple_helper<yk::ref_placeholder_t<T>, Ts...> {
using type = prepend_tuple_t<T, typename ref_invoke_tuple_helper<Ts...>::type>;
};
template <class... Ts>
using ref_invoke_tuple_helper_t = typename ref_invoke_tuple_helper<Ts...>::type;
template <class F, class... Args>
constexpr auto ref_invoke(F&& f, Args&&... args) {
ref_invoke_tuple_helper_t<std::remove_cvref_t<Args>...> val;
[&]<std::size_t... Is>(std::index_sequence<Is...>) { //
std::invoke(std::forward<F>(f), get_or_forward<Args, Is, Args...>(std::forward<Args>(args), val)...);
}(std::index_sequence_for<Args...>{});
return val;
}
} // namespace yk
int main() { //
auto f = [](auto& x, auto val, auto& y) {
x = val + 33;
y = val + 4;
};
auto res = yk::ref_invoke(f, yk::ref<int>, 42, yk::ref<int>);
std::println("{}", res);
}