Boost.TypeErasure で特定の関数で多重定義されているオブジェクトを保持する

さて、Boost.TypeErasure は基本的に保持する型に対してメンバ関数などを要求するのですが、次のように多重定義された関数を呼び出すことで、型に対して非侵入的に Concept を要求する事が出来ます。

[ソース]

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/mpl/vector.hpp>
#include <iostream>


template<typename T>
void
disp(T const& t){
    std::cout << t << std::endl;
}


template<typename T = boost::type_erasure::_self>
struct displayable{
    static void apply(T const& t){
        disp(t);
    }
};

void
disp(boost::type_erasure::_self){}

namespace boost{
namespace type_erasure{

template<typename T, typename Base>
struct concept_interface< ::displayable<T>, Base, T> : Base{
    void
    disp() const{
        call(::displayable<T>(), *this);
    }
};

}  // namespace type_erasure
}  // namespace boost

template<typename Concept, typename T>
void
disp(boost::type_erasure::any<Concept, T> const& t){
    t.disp();
//     boost::type_erasure::call(::displayable<>(), t);
}



#include <string>


void
disp(std::string const& str){
	std::cout << "str :" << str << std::endl;
	std::cout << "size:" << str.size() << std::endl;
}


struct X{
    X(int value) : value(value){}
    int value;
};


// X のメンバを実装するのではなくて disp 関数をオーバーロードする
void
disp(X const& x){
    std::cout << x.value << std::endl;
}


int
main(){
    namespace te = boost::type_erasure;
    
    // disp 関数に渡す事が出来る型を保持する
    typedef te::any<
        boost::mpl::vector<
            displayable<>,
            te::copy_constructible<>,
            te::relaxed_match
        >
    > any_disp;

    any_disp a(10);

    disp(a);
    
    a = any_disp(std::string("homu"));
    disp(a);

    X x(42);
    a = any_disp(x);
    disp(a);


    return 0;
}

[出力]

10
str :homu
size:4
42


こんな感じで、disp() をオーバーロードしている型であれば問題なく処理することが出来ます。
つまり既存の型を変更しなくても関数のオーバーロードさえ書いておけば any で保持することが出来ます。
これは地味に強力な気がする。


ただし、戻り値型は Concept を定義する時に決める必要があるので、型によって戻り値型を変えるとか言う事は難しいかなぁ。