読者です 読者をやめる 読者になる 読者になる

function + bindのType Erasureでオブジェクトのコピーを持つ

C++

function + bindを使ったType Erasure


オブジェクトをboost::anyでメンバに持ち、anyにコピーしたオブジェクトを元の型に変換してbind。
boost::any_cast(obj_)だと余計なコピーが発生してしまうので、any_castにはポインタを渡している。
メンバ変数の宣言順(初期化順)に注意、obj_が最初。

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/any.hpp>

class GameScene {
    boost::any obj_;
    boost::function<void()> update_func_;
    boost::function<void()> draw_func_;
public:

    GameScene() {}

    template <class T>
    GameScene(const T& obj) :
        obj_(obj),
        update_func_(boost::bind(&T::update, boost::any_cast<T>(&obj_))),
        draw_func_(boost::bind(&T::draw, boost::any_cast<T>(&obj_))) {}

    template <class T>
    GameScene& operator=(const T& obj)
    {
        obj_ = obj;
        update_func_ = boost::bind(&T::update, boost::any_cast<T>(&obj_));
        draw_func_ = boost::bind(&T::draw, boost::any_cast<T>(&obj_));
        return *this;
    }

    void update()
    {
        update_func_();
    }

    void draw() const
    {
        draw_func_();
    }

    bool is_empty() const
    {
        return obj_.empty() || update_func_.empty() || draw_func_.empty();
    }
};

#include <iostream>
#include <boost/current_function.hpp>

struct Title {
    void update()
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    void draw() const
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }
};

struct Game {
    void update()
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    void draw() const
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }
};

int main()
{
    GameScene current_scene = Title();

    current_scene.update();
    current_scene.draw();
    
    current_scene = Game();
    current_scene.update();
    current_scene.draw();
}

anyはともかく、functionのコストをいかに下げるかが今後の課題。
自分が使う分には今のままでもいいのだが。