Boost logo

Boost :

From: Mac Murrett (mmurrett_at_[hidden])
Date: 2002-06-02 14:52:20


I am currently working on a project in which I would use
boost::any, but I need a variant type that supports streaming. Of
course, this variant type would only be able to hold streamable
types, so adding this functionality to any would be inappropriate.
This led me to think that there could be value in adding a template
parameter to any (thus forming any2) that would allow access to its
internal type.

The mechanism that I propose is to move holder and placeholder out
into a class named basic_any2_parent, and modify them slightly.
any2 will derive from its template parameter, which will be this by
default:

     template<class Any2Parent = basic_any2_parent>
     class any2: public Any2Parent

In its implementation, any2 will use Any2Parent::holder and
Any2Parent::placeholder in place of holder and placeholder.

The basic_any2_parent class is designed to make subclassing it
easy, while allowing its implementation to continue to be valid,
hence holder is also templatized on Any2Parent, and derives from
Any2Parent::placeholder. Furthermore, holder::clone creates a new
Any2Parent::holder. The implementation of basic_any2_parent
follows:

     class basic_any2_parent
     {
       protected:
         class placeholder
         {
         public: // structors

             virtual ~placeholder()
             {
             }

         public: // queries

             virtual const std::type_info & type() const = 0;

             virtual placeholder * clone() const = 0;
         };

         template<typename ValueType, class Any2Parent =
basic_any2_parent>
         class holder: public Any2Parent::placeholder
         {
         public: // structors

             holder(const ValueType & value)
               : held(value)
             {
             }

         public: // queries

             virtual const std::type_info & type() const
             {
                 return typeid(ValueType);
             }

             virtual placeholder * clone() const
             {
                 return new Any2Parent::holder<ValueType,
Any2Parent>(held);
             }

         public: // representation

             ValueType held;

         };
     };

The idea here is to allow an end-user to subclass
basic_any2_parent, provide customized placeholder and holder
classes, and have the existing holder implementation still work.
As an example of this, a new any2 parent parent class that supports
streaming follows:

class streamable_any2_parent: public boost::basic_any2_parent
{
   protected:
     class placeholder: public boost::basic_any2_parent::placeholder
     {
       public:
         virtual void dump(std::ostream &out) = 0;
     };

     template<typename ValueType, class>
     class holder: public
boost::basic_any2_parent::holder<ValueType, streamable_any2_parent>
     {
       public:
         holder(const ValueType & value)
           : boost::basic_any2_parent::holder<ValueType,
streamable_any2_parent>(value)
         {
         }
       public:
         virtual void dump(std::ostream &out)
         {
             out << held;
         }
     };

   private:
     static void dump(std::ostream &out, const
boost::any2<streamable_any2_parent> &value)
     {
         value.content->dump(out);
     }

   public:
     friend std::ostream &operator<<(std::ostream &out, const
boost::any2<streamable_any2_parent> &value);
};

inline std::ostream &operator<<(std::ostream &out, const
boost::any2<streamable_any2_parent> &value)
{
     streamable_any2_parent::dump(out, value);
     return(out);
}

There are also other details in the implementation of any2 that
make this possible (in particular, any2 considers Any2Parent a
friend), but this should give a basic idea of the goals and
proposed solution. The entirety of any2.hpp is attached.

Comments/suggestions?

Thanks,
Mac Murrett.


#ifndef BOOST_ANY2_INCLUDED
#define BOOST_ANY2_INCLUDED

// what: variant type boost::any2
// who: contributed by Mac Murrett
// based on boost::any by Kevlin Henney,
// with features contributed and bugs found by
// Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when: June 2002
// where: tested with MWCW 7.2

#include <algorithm>
#include <typeinfo>

#include "boost/config.hpp"

namespace boost
{
    class basic_any2_parent
    {
      protected:
        class placeholder
        {
        public: // structors
    
            virtual ~placeholder()
            {
            }

        public: // queries

            virtual const std::type_info & type() const = 0;

            virtual placeholder * clone() const = 0;
        };

        template<typename ValueType, class Any2Parent = basic_any2_parent>
        class holder: public Any2Parent::placeholder
        {
        public: // structors

            holder(const ValueType & value)
              : held(value)
            {
            }

        public: // queries

            virtual const std::type_info & type() const
            {
                return typeid(ValueType);
            }

            virtual placeholder * clone() const
            {
                return new Any2Parent::holder<ValueType, Any2Parent>(held);
            }

        public: // representation

            ValueType held;

        };
    };

    template<class Any2Parent = basic_any2_parent>
    class any2: public Any2Parent
    {
    public: // structors

        any2()
          : content(0)
        {
        }

        template<typename ValueType>
        any2(const ValueType & value)
          : content(new holder<ValueType, Any2Parent>(value))
        {
        }

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

        ~any2()
        {
            delete content;
        }

    public: // modifiers

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

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

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

    public: // queries

        bool empty() const
        {
            return !content;
        }

        const std::type_info & type() const
        {
            return content ? content->type() : typeid(void);
        }

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // types
#else
    public: // types (public so any2_cast can be non-friend)
#endif

        using Any2Parent::placeholder;
        using Any2Parent::holder;

    private:
        friend class Any2Parent;

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

    private: // representation

        template<typename ValueType>
        friend ValueType * any2_cast(any2 *);

#else

    public: // representation (public so any2_cast can be non-friend)

#endif

        Any2Parent::placeholder * content;

    };

    class bad_any2_cast : public std::bad_cast
    {
    public:
        virtual const char * what() const throw()
        {
            return "boost::bad_any2_cast: "
                   "failed conversion using boost::any2_cast";
        }
    };

    template<typename ValueType, class Any2Parent>
    ValueType * any2_cast(any2<Any2Parent> * operand)
    {
        return operand && operand->type() == typeid(ValueType)
                    ? &static_cast<any2::holder<ValueType> *>(operand->content)->held
                    : 0;
    }

    template<typename ValueType, class Any2Parent>
    const ValueType * any2_cast(const any2<Any2Parent> * operand)
    {
        return any2_cast<ValueType>(const_cast<any2 *>(operand));
    }

    template<typename ValueType, class Any2Parent>
    ValueType any2_cast(const any2<Any2Parent> & operand)
    {
        const ValueType * result = any2_cast<ValueType>(&operand);
        if(!result)
            throw bad_any2_cast();
        return *result;
    }

}

// Copyright Kevlin Henney, 2000, 2001. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives, and that no
// charge may be made for the software and its documentation except to cover
// cost of distribution.
//
// This software is provided "as is" without express or implied warranty.

#endif



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk