Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#include <type_traits>
#include <utility>
#ifdef __clang__
namespace std
{
template <typename T, typename... Ts>
using is_invocable = std::is_callable<T(Ts...)>;
}
#endif
template <typename>
class function_view;
template <typename R, typename... Args>
constexpr bool operator==(const function_view<R(Args...)>& fv,
std::nullptr_t) noexcept;
template <typename R, typename... Args>
class function_view<R(Args...)>
{
private:
using signature_type = R(void*, Args...);
void* _ptr;
signature_type* _erased_fn;
template <typename F>
static constexpr R erased_fn(void* ptr, Args... xs) noexcept(noexcept(
std::forward<F>((*reinterpret_cast<std::add_pointer_t<F>>(ptr)))(
std::forward<Args>(xs)...)))
{
return std::forward<F>((*reinterpret_cast<std::add_pointer_t<F>>(ptr)))(
std::forward<Args>(xs)...);
}
template <typename F>
using valid_invocable =
std::enable_if_t<std::is_invocable<F&&, Args...>{} &&
!std::is_same<std::decay_t<F>, function_view>{}>;
public:
constexpr function_view() noexcept : function_view{nullptr}
{
}
constexpr function_view(std::nullptr_t) noexcept : _ptr{nullptr}
{
}
constexpr function_view(const function_view& rhs) noexcept
: _ptr{rhs._ptr}, _erased_fn{rhs._erased_fn}
{
}
template <typename F, typename = valid_invocable<F>>
constexpr function_view(F&& f) noexcept
: _ptr{(void*)std::addressof(f)}, _erased_fn{&erased_fn<F&&>}
{
}
constexpr function_view& operator=(const function_view& rhs) noexcept
{
_ptr = rhs._ptr;
_erased_fn = rhs._erased_fn;
return *this;
}
constexpr function_view& operator=(std::nullptr_t) noexcept
{
_ptr = nullptr;
return *this;
}
template <typename F, typename = valid_invocable<F>>
constexpr function_view& operator=(F&& f) noexcept
{
_ptr = (void*)std::addressof(f);
_erased_fn = &erased_fn<F&&>;
}
constexpr void swap(function_view& rhs)
{
using std::swap;
swap(_ptr, rhs._ptr);
swap(_erased_fn, rhs._erased_fn);
}
constexpr explicit operator bool() const noexcept
{
return _ptr != nullptr;
}
constexpr R operator()(Args... xs) const
noexcept(noexcept(_erased_fn(_ptr, std::forward<Args>(xs)...)))
{
return _erased_fn(_ptr, std::forward<Args>(xs)...);
}
friend constexpr bool operator==
<>(const function_view<R(Args...)>& fv, std::nullptr_t) noexcept;
};
template <typename R, typename... Args>
constexpr void swap(function_view<R(Args...)>& lhs,
function_view<R(Args...)>& rhs)
{
lhs.swap(rhs);
}
template <typename R, typename... Args>
constexpr bool operator==(const function_view<R(Args...)>& fv,
std::nullptr_t) noexcept
{
return fv._ptr == nullptr;
}
template <typename R, typename... Args>
constexpr bool operator==(std::nullptr_t,
const function_view<R(Args...)>& fv) noexcept
{
return fv == nullptr;
}
template <typename R, typename... Args>
constexpr bool operator!=(const function_view<R(Args...)>& fv,
std::nullptr_t) noexcept
{
return !(fv == nullptr);
}
template <typename R, typename... Args>
constexpr bool operator!=(std::nullptr_t,
const function_view<R(Args...)>& fv) noexcept
{
return !(fv == nullptr);
}
constexpr void fff()
{
function_view<void(int)> fv = [](int) {};
fv(9);
}
constexpr int test(int y)
{
function_view<int(int)> fv = [](int x) { return x * 2; };
return fv(y);
}
int main()
{
function_view<void(int)> fv = [](int) {};
fv(9);
fff();
fv == nullptr;
static_assert(test(4) == 8);
}
/*
TODO:
* figure out if it's possible to have `constexpr operator()`
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.