Skip to content

Instantly share code, notes, and snippets.

@derrickturk
Last active October 4, 2020 21:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save derrickturk/4744ddc676bed24840dceb23ed822fef to your computer and use it in GitHub Desktop.
Save derrickturk/4744ddc676bed24840dceb23ed822fef to your computer and use it in GitHub Desktop.
messing around with concepts and type erasure in C++20
#include <exception>
#include <iostream>
#include <utility>
#include <memory>
#include <vector>
#include <concepts>
template<class T> concept IntFn = requires (T t) {
{t(0)} -> std::same_as<int>;
};
class any_int_fn {
public:
template<IntFn Fn> any_int_fn(Fn fn)
: pimpl_(std::make_unique<impl_<Fn>>(std::move(fn))) { }
any_int_fn(const any_int_fn& other)
: pimpl_(other.pimpl_->clone()) { }
any_int_fn(any_int_fn&& other) = default;
int operator()(int x) {
if (!pimpl_)
throw std::runtime_error("attempt to call after move");
return (*pimpl_)(x);
}
private:
class impl_base_ {
public:
virtual ~impl_base_() = default;
virtual int operator()(int) = 0;
virtual std::unique_ptr<impl_base_> clone() const = 0;
};
template<IntFn Fn>
class impl_: public impl_base_ {
public:
impl_(Fn fn) : fn_(std::move(fn)) { }
int operator()(int x) override { return fn_(x); }
std::unique_ptr<impl_base_> clone() const override
{
return std::make_unique<impl_<Fn>>(fn_);
}
private:
Fn fn_;
};
std::unique_ptr<impl_base_> pimpl_;
};
auto doItTo3(IntFn auto&& fn) { return fn(3); }
int times_seven(int x)
{
return x * 7;
}
int main()
{
std::cout << doItTo3([](int x) { return x + 5; }) << '\n';
const int a = 3;
int b = 4;
any_int_fn af { times_seven };
std::cout << doItTo3(af) << '\n';
std::vector<any_int_fn> fns;
fns.emplace_back([](int x) { return x + 5; });
fns.emplace_back([](int x) { return x + 5; });
fns.emplace_back([=](int x) { return x + a; });
fns.emplace_back([&](int x) { return x - b; });
fns.emplace_back(times_seven);
fns.emplace_back(std::move(af));
// this would throw!
// std::cout << doItTo3(af) << '\n';
for (auto &fn : fns) {
std::cout << doItTo3(fn) << '\n';
}
b = 7;
for (auto &fn : fns) {
std::cout << doItTo3(fn) << '\n';
}
// this would fail concept checking
// any_int_fn hmm { [=](int x) { return x || "yo"; } };
// incurs clones, though...
std::vector ezfns {
any_int_fn { [](int x) { return x - 7; } },
any_int_fn { [=](int x) { return x - 7; } },
};
for (auto &fn : ezfns) {
std::cout << doItTo3(fn) << '\n';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment