#include <functional>
#include <vector>
#include <cassert>
#include <iostream>
#include <memory>
#include <SFML/Graphics.hpp>
////////////////////////// Any Class ////////////////////////////////
class AnyFunction
{
struct placeholder
{
virtual ~placeholder() = default;
};
template <typename F>
struct holder : placeholder
{
holder(F&& f) : data(std::forward<F>(f)) {}
F data;
};
public:
template <typename F>
AnyFunction(F&& f)
: mContent(std::make_shared<holder<std::decay_t<F>>>(std::forward<F>(f)))
{
}
template <typename F>
const F& cast() const
{
assert(dynamic_cast<const holder<F>*>(mContent.get()) != nullptr);
return static_cast<const holder<F>&>(*mContent).data;
}
private:
std::shared_ptr<placeholder> mContent = nullptr;
};
////////////////////////// Function Holder //////////////////////////
class FunctionHolder
{
public:
template <typename T, typename R, typename... Ts>
void insert(T&& t, R(T::*method)(Ts...))
{
using namespace std::placeholders;
mHolder.emplace_back(std::function<R(Ts...)>(std::bind(method, std::forward<T>(t), _1)));
}
template <typename... Ts>
void call(Ts&&... ts)
{
for (auto&& fn : mHolder)
{
fn.cast<std::function<void(Ts...)>>()(std::forward<Ts>(ts)...);
}
}
private:
std::vector<AnyFunction> mHolder;
};
////////////////////////// Test /////////////////////////////////////
struct Player : public sf::Transformable
{
Player()
: shape(100.f)
{
shape.setFillColor(sf::Color::Cyan);
}
void update(sf::Time dt)
{
std::cout << dt.asSeconds() << "Player update\n";
}
void draw(sf::RenderWindow& window)
{
window.draw(shape, getTransform());
}
private:
sf::CircleShape shape;
};
struct Enemy : public sf::Transformable
{
Enemy()
: shape(100.f)
{
shape.setFillColor(sf::Color::Red);
}
void update(sf::Time dt)
{
std::cout << dt.asSeconds() << "Enemy update\n";
}
void draw(sf::RenderWindow& window)
{
window.draw(shape, getTransform());
}
private:
sf::CircleShape shape;
};
int main()
{
sf::RenderWindow window({ 800, 600 }, "test");
Player player;
player.setPosition(100, 100);
Enemy enemy;
enemy.setPosition(400, 300);
FunctionHolder updater;
updater.insert(std::move(player), &Player::update);
updater.insert(std::move(enemy), &Enemy::update);
FunctionHolder drawer;
drawer.insert(std::move(player), &Player::draw);
drawer.insert(std::move(enemy), &Enemy::draw);
sf::Clock clock;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
sf::Time dt = clock.restart();
updater.call(dt);
window.clear();
drawer.call(window);
window.display();
}
}