Skip to content

Instantly share code, notes, and snippets.

@ecatmur
Last active May 24, 2016 07:32
Show Gist options
  • Save ecatmur/e7953d71e09862205c60002e33aa9efd to your computer and use it in GitHub Desktop.
Save ecatmur/e7953d71e09862205c60002e33aa9efd to your computer and use it in GitHub Desktop.
#include <cstring>
#include <functional>
#include <iostream>
#include <new>
#include <utility>
template<std::size_t Size>
class TrivialBuffer
{
public:
std::aligned_storage_t<Size, std::alignment_of<void*>::value> buf;
TrivialBuffer() = default;
template<class T>
TrivialBuffer(T t) {
static_assert(sizeof(t) <= sizeof(buf));
static_assert(std::alignment_of<T>::value <= std::alignment_of<decltype(buf)>::value);
// static_assert(std::is_trivially_copy_constructible<T>::value);
static_assert(std::is_trivially_destructible<T>::value);
std::memcpy(&buf, &t, sizeof(t));
}
};
using TrivialFunctionBuffer = TrivialBuffer<sizeof(void*) * 3>;
template<class Signature, class Derived>
class FunctionInvoker;
template<class Ret, class... Args, class Derived>
class FunctionInvoker<Ret(Args...), Derived>
{
public:
using Invoker = Ret(void const*, Args...);
Invoker* invoker;
FunctionInvoker(Invoker* i) : invoker{i} {};
template<class F>
static Ret invoke(void const* obj, Args... args) {
return (*reinterpret_cast<std::decay_t<F> const*>(obj))
(std::forward<Args>(args)...);
}
static Ret invokeBad(void const*, Args...) {
throw std::bad_function_call();
}
Ret operator()(Args... args) const {
return invoker(Derived::get(this), std::forward<Args>(args)...);
}
};
template<class Signature>
class TrivialFunction
: private TrivialFunctionBuffer
, private FunctionInvoker<Signature, TrivialFunction<Signature>>
{
using This = TrivialFunction<Signature>;
using Invoker = FunctionInvoker<Signature, This>;
friend Invoker;
static void const* get(Invoker const* self) {
return &static_cast<This const*>(self)->buf;
}
public:
template<class F>
TrivialFunction(F f)
: TrivialFunctionBuffer(f)
, Invoker{&Invoker::template invoke<F>} {}
TrivialFunction()
: TrivialFunctionBuffer{}
, Invoker{&Invoker::invokeBad} {}
bool operator!() const {
return Invoker::invoker != &Invoker::invokeBad; }
explicit operator bool() const { return !!*this; }
using Invoker::operator();
};
static_assert(std::is_trivially_destructible<TrivialFunction<void()>>::value);
static_assert(sizeof(TrivialFunction<void()>) == sizeof(void*) * 4);
double f(TrivialFunction<double(int, int)>& x, int i, int j) {
return x(i, j);
}
bool g(TrivialFunction<double(int, int)>& x) {
return !!x;
}
int main() {
TrivialFunction<void(int)> f;
f = [j = 5](int i) { std::cout << i + j; };
f(42);
f = [](int i) { std::cout << i; };
f(99);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment