Skip to content

Instantly share code, notes, and snippets.

@Morwenn
Created September 28, 2025 09:41
Show Gist options
  • Select an option

  • Save Morwenn/ed6af6fc1185d0dc591c51fef8407d43 to your computer and use it in GitHub Desktop.

Select an option

Save Morwenn/ed6af6fc1185d0dc591c51fef8407d43 to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2025 Morwenn
* SPDX-License-Identifier: CC0-1.0
*/
// Make an std::index_sequence in reverse order
template<std::size_t Index, std::size_t... Indices>
struct make_reversed_index_sequence:
make_reversed_index_sequence<Index - 1, Indices..., Index - 1>
{};
template<std::size_t... Indices>
struct make_reversed_index_sequence<0, Indices...>:
std::index_sequence<Indices...>
{};
// Type returned by flip
template<typename F>
struct flip_t
{
private:
F func;
// Forward *this cv-ref and invert order of parameters
template<typename Self, typename Tuple, std::size_t... Indices>
static auto _call(Self&& self, Tuple&& args, std::index_sequence<Indices...>)
-> decltype(std::invoke(
std::forward<Self>(self).func,
std::get<Indices>(std::forward<Tuple>(args))...
))
{
return std::invoke(
std::forward<Self>(self).func,
std::get<Indices>(std::forward<Tuple>(args))...
);
}
template<typename Self, typename Tuple>
static auto _call(Self&& self, Tuple&& args)
-> decltype(_call(
std::forward<Self>(self),
std::forward<Tuple>(args),
make_reversed_index_sequence<std::tuple_size_v<Tuple>>{}
))
{
return _call(
std::forward<Self>(self),
std::forward<Tuple>(args),
make_reversed_index_sequence<std::tuple_size_v<Tuple>>{}
);
}
public:
// Construction
flip_t() = default;
explicit constexpr flip_t(F&& func):
func(std::move(func))
{}
// Call
template<typename... Args>
constexpr auto operator()(Args&&... args) &
-> decltype(_call(*this, std::forward_as_tuple(std::forward<Args>(args)...)))
{
return _call(*this, std::forward_as_tuple(std::forward<Args>(args)...));
}
template<typename... Args>
constexpr auto operator()(Args&&... args) const&
-> decltype(_call(*this, std::forward_as_tuple(std::forward<Args>(args)...)))
{
return _call(*this, std::forward_as_tuple(std::forward<Args>(args)...));
}
template<typename... Args>
constexpr auto operator()(Args&&... args) &&
-> decltype(_call(*this, std::forward_as_tuple(std::forward<Args>(args)...)))
{
return _call(*this, std::forward_as_tuple(std::forward<Args>(args)...));
}
template<typename... Args>
constexpr auto operator()(Args&&... args) const&&
-> decltype(_call(*this, std::forward_as_tuple(std::forward<Args>(args)...)))
{
return _call(*this, std::forward_as_tuple(std::forward<Args>(args)...));
}
// Accessor
[[nodiscard]]
constexpr auto base() const
-> F
{
return func;
}
};
// flip
template<typename F>
constexpr auto flip(F func)
-> flip_t<F>
{
return flip_t<F>(std::move(func));
}
template<typename F>
constexpr auto flip(flip_t<F> flipped_func)
-> F
{
return flipped_func.base();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment