class.hpp

Back to Class wrapping

pastel/sys/generic/

#ifndef PASTELSYS_CLASS_HPP
#define PASTELSYS_CLASS_HPP

#include "pastel/sys/generic/class.h"
#include "pastel/sys/mytypes.h"
#include "pastel/sys/hashing.h"

#include <boost/operators.hpp>

#include <utility>
#include <type_traits>

namespace Pastel
{

    template <
        typename Type, 
        typename Tag>
    class Member_Class
    {
    public:
        // We require that Type be a non-class, since otherwise
        // the constructor forwarding turns all constructors
        // implicit.
        PASTEL_STATIC_ASSERT(!std::is_class<Type>::value);

        template <
            typename... That,
            // Forward only those parameters which can be used to construct Type.
            Requires<std::is_constructible<Type, That...>> = 0
        >
        Member_Class(That&&... that)
            : member_(std::forward<That>(that)...)
        {
        }

        operator Type&()
        {
            return member_;
        }

        operator const Type&() const
        {
            return member_;
        }

    private:
        Type member_;
    };

    template <typename Tag>
    class Member_Class<void, Tag>
    : boost::less_than_comparable<Member_Class<void, Tag>,
    boost::equality_comparable<Member_Class<void, Tag>
    > >
    {
    public:
        Member_Class()
        {
        }

        Member_Class(std::nullptr_t)
        {
        }

        bool operator<(const Member_Class& that) const
        {
            return false;
        }

        bool operator==(const Member_Class& that)
        {
            return true;
        }
    };

}

namespace std
{

    template <
        typename Type,
        typename Tag>
    struct hash<Pastel::Member_Class<Type, Tag>>
    {
    public:
        Pastel::hash_integer operator()(
            const Pastel::Member_Class<Type, Tag>& that) const
        {
            return Pastel::computeHash<Type>(that);
        }
    };

    template <
        typename Tag>
    struct hash<Pastel::Member_Class<void, Tag>>
    {
    public:
        Pastel::hash_integer operator()(
            const Pastel::Member_Class<void, Tag>& that) const
        {
            return Pastel::computeHash<void*>(0);
        }
    };

}

namespace Pastel
{

    template <
        typename Type, 
        typename Tag>
    class Inherited_Class
    : public Type
    {
    public:
        // We require Type to be a class; we inherit from Type.
        PASTEL_STATIC_ASSERT(std::is_class<Type>::value);

        //! Inherit most of the constructors from Type.
        /*!
       It is important to use inheritance --- rather than perfect 
       forwarding --- to preserve the explicitness of Type's
       constructors.
       */
        using Type::Type;

        //! Constructs an empty class.
        /*!
       The default-constructor is not lifted from Type.
       */
        Inherited_Class()
        : Type()
        {
        }

        //! Forwards copy-construction to Type.
        /*! 
       The copy-constructor is not lifted from Type.
       */
        Inherited_Class(const Type& that)
        : Type(that)
        {
        }

        //! Forwards move-construction to Type.
        /*! 
       The move-constructor is not lifted from Type.
       */
        Inherited_Class(Type&& that)
        : Type(std::move(that))
        {
        }

        //! Forwards assignment to Type.
        template <typename That>
        Inherited_Class& operator=(That&& that)
        {
            *static_cast<Type*>(this) = std::forward<That>(that);
            return *this;
        }
    };

}

namespace std
{

    template <
        typename Type,
        typename Tag>
    struct hash<Pastel::Inherited_Class<Type, Tag>>
    {
    public:
        Pastel::hash_integer operator()(
            const Pastel::Inherited_Class<Type, Tag>& that) const
        {
            return Pastel::computeHash<Type>(that);
        }
    };

}

#endif