Boost.TypeErasure でタスク処理

C++ タスク処理といえば、継承を使用した多態性で実装するのが一般的(だと思う)のですが、Boost.TypeErasure でちょっと実装してみました。

[ソース]

#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/iterator.hpp>
#include <boost/type_erasure/callable.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/relaxed_match.hpp>
#include <boost/type_erasure/member.hpp>

#include <boost/mpl/vector.hpp>
#include <vector>
#include <string>


BOOST_TYPE_ERASURE_MEMBER((has_init), init, 0)
BOOST_TYPE_ERASURE_MEMBER((has_update), update, 1)
BOOST_TYPE_ERASURE_MEMBER((has_render), render, 1)


struct counter{
    void init(){
        count = 0;
    }

    bool update(int frame){
        if( frame % 2 == 0 ){
            ++count;
        }
        return count < max;
    }

    void render(std::ostream& os) const{
        os << name << ":" << count << std::endl;
    }

    std::string name;
    int max;
    int count;
};


struct homu{
    void init(){}

    bool update(int){
        ++count;
        return true;
    }

    void render(std::ostream& os) const{
        for(int n = 0 ; n < count ; ++n){
            os << "homu";
        }
        os << std::endl;
    }

    int count = 0;
};


struct frame_counter{
    void init(){
        counter = 0;
    }

    bool update(int){
        ++counter;
        return true;
    }

    void render(std::ostream& os) const{
        os << "frame: " << counter << std::endl;
    }

    int& counter;
};


int
main(){
    namespace te = boost::type_erasure;
    namespace mpl = boost::mpl;

    typedef boost::mpl::vector<
        ::has_init<void()>,
        ::has_update<bool(int)>,
        ::has_render<void(std::ostream&)>,
        te::copy_constructible<>
    > task_requires;

    typedef te::any<task_requires> task_concept;
    
    std::vector<task_concept> tasks;

    int frame_count = 0;
    tasks.emplace_back(frame_counter{frame_count});

    tasks.emplace_back(counter{"homu",   5, 0});
    tasks.emplace_back(counter{"mado",  42, 0});
    tasks.emplace_back(counter{"mami",  15, 0});
    tasks.emplace_back(counter{"saya",   9, 0});
    tasks.emplace_back(counter{"an",    25, 0});
    tasks.emplace_back(homu{});

    for(auto&& x : tasks){
        x.init();
    }

    while(1){
        system("cls");
        for(auto&& x : tasks){
            if(!x.update(frame_count) ){
                x.init();
            }
            x.render(std::cout);
        }
    }

    return 0;
}

[出力例]

homu:3
mado:13
mami:13
saya:4
an:13
homuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomuhomu


だいぶ素直に、すっきりとした実装になっていますね。
メンバ関数の引数はコンパイル時に決定する必要がありますが、そこも Boost.TypeErasure を使用すれば、もうちょっと高い抽象化を実現することが出きそうですね。
(Boost.TypeErasure を使用するオーバーヘッドが気になるけど。
いくつか C++11 の機能を使っていますが、基本的には C++03 でも動作するはず。