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

型安全操作が可能なany(しょぼい版)

C++

Boost.Spiritの中にあるhold_anyにストリーム演算子があるのを思い出して、もしかして型安全操作書けるんじゃないかなーと思って書いてみた。
とりあえず関数ひとつ指定できるようにしただけで、any_castも何もできませんが、今後なにかおもしろいことを思いつくかもしれません。関数オブジェクトのfusion::mapを簡単に指定できるようにすればいいのかもしれない。

#include <iostream>
#include "any.hpp"
#include <boost/phoenix.hpp>

struct disper {
    template <class T>
    void operator()(const T& x) const
    {
        std::cout << x << std::endl;
    }
};

namespace phx = boost::phoenix;
using phx::arg_names::_1;

int main()
{
    // 中に入ってる値を表示する
    {
        shand::any x(1, disper());
        x.invoke();
    }
    // 中に入ってる値を抽出する
    {
        int extract = 0;

        shand::any x(3, (phx::ref(extract) = _1));
        x.invoke();

        disper()(extract);
    }
}
1
3
#ifndef SHAND_ANY_INCLUDE
#define SHAND_ANY_INCLUDE

#include <algorithm>
#include <typeinfo>
#include <boost/assert.hpp>

namespace shand {

class any {
public:

    any()
      : content(0)
    {
    }

    template<typename ValueType, typename F>
    any(const ValueType& value, F f)
      : content(new holder<ValueType, F>(value, f))
    {
    }

    any(const any& other)
      : content(other.content ? other.content->clone() : 0)
    {
    }

    ~any()
    {
        delete content;
    }

public:

    any& swap(any& rhs)
    {
        std::swap(content, rhs.content);
        return *this;
    }

    template<typename ValueType>
    any& operator=(const ValueType& rhs)
    {
        any(rhs).swap(*this);
        return *this;
    }

    any& operator=(any rhs)
    {
        rhs.swap(*this);
        return *this;
    }

public:

    bool empty() const
    {
        return !content;
    }

    void invoke()
    {
        BOOST_ASSERT(content);
        content->invoke();
    }

private:

    class placeholder
    {
    public:
        virtual ~placeholder() {}
        virtual placeholder* clone() const = 0;
        virtual void invoke() = 0;

    };

    template<typename ValueType, typename F>
    class holder : public placeholder
    {
    public:

        holder(const ValueType& value, F f)
          : held(value), f(f)
        {
        }

        virtual placeholder* clone() const
        {
            return new holder(held, f);
        }

        virtual void invoke()
        {
            f(held);
        }

    public:
        ValueType held;
        F f;

    private:
        holder& operator=(const holder&);
    };

public:
    placeholder* content;

};

} // namespace shand

#endif // SHAND_ANY_INCLUDE