RTTI を使わずに Boost.Any を実装する方法

Boost.Any は any_cast<> 内で type_info を使って変換しようとしている型が一致しているかどうかを判断してるんだけど、RTTI を使いたくないので type_info を使わずに any を実装してみる。


これは要するに型単位でユニークな値が取れればいいだけなので、

namespace any_detail
{
    template<class ValueType>
    struct dummy { static void f() { } };
}
typedef void (*type_id)();
template<class ValueType>
type_id get_type_id() { return &any_detail::dummy<ValueType>::f; }

こんなのを作っておけば、あとは type_info を返す代わりに get_type_id を使うだけ。

template<typename ValueType>
class holder : public placeholder
{
    ...

    //virtual const type_info& type() const
    //{
    //    return typeid(ValueType);
    //}
    virtual type_id type() const
    {
        return get_type_id<ValueType>();
    }

    ...
};
template<typename ValueType>
ValueType * any_cast(any * operand)
{
    return operand && operand->type() == get_type_id<ValueType>()/*typeid(ValueType)*/
                ? &static_cast<any::holder<ValueType> *>(operand->content)->held
                : 0;
}

これで RTTI を使わなくても any を実装することができる。


でも cv 修飾なんかある場合はどうなるんだろう?
typeid(const int) と typeid(int) が異なるなら問題ないんだけど、同じなら remove_cv する必要があるかも。


とりあえず移植したのは↓のページに入れておきました。
http://melpon.tank.jp/pukiwiki147/index.php?cmd=read&page=Memo%2F%CA%AA%C3%D6%2Fmoost


追記:
id:xyuyux さんから報告を頂いたのですが、どうやら VC9 の Release だと最適化の段階で &dummy::f や &dummy::f を共通化するらしく、同じポインタになっちゃうようです。
最適化なんて嫌いだー!と叫んでたら id:DigitalGhost さんから解決策を頂きました。

namespace any_detail
{
    template<class ValueType> struct dummy { static char p; };
    template<class ValueType> char dummy<ValueType>::p;
}
typedef void* type_id;
template<class ValueType>
type_id get_type_id() { return &any_detail::dummy<ValueType>::p; }

なるほど……確かにこれは共通化できなさそうです。ということで Wiki の方も修正しておきました。


お二方ともありがとうございます。最適化大好きです。