Last active
July 3, 2017 14:17
-
-
Save vittorioromeo/689b773d642afe663a3b296e5fbd10d4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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