Boost logo

Boost :

From: Tony D (tony_in_da_uk_at_[hidden])
Date: 2005-11-01 10:52:25


Larry wrote:
> So if I had:
> struct sname_t
> { string first_m;
> string last_m;
> };
> sname_t a_sname;
> a_sname.first_m="first";
> a_sname.last_m="last";
> then, to convert this to using typemaps, I would do:
> struct fname_t: public string{...};
> struct lname_t: public string{...};
> NS:type_map<fname_t,lname_t> mname_t;
> mname_t a_mname;
> a_mname = fname_t("first");
> a_mname = lname_t("last");
> So I don't see that I've gained much, at least in
> this case.

Firstly, I left too much of the fleshing out possible
from the type_map abstraction implicit, which
certainly left room for your question (sorry).

Consider:

    a_mname = x.get_last_name();

Benefits include:

* Code using type_maps can speculatively store values
(with mismatches reported by the compiler) without
needing to know specifics of the types or field
identifiers:

     e.g. template <class FUNCTOR>
           ...(const FUNCTOR& functor)...
               a_mname = functor(x, y, z);

* You can iterate over the fields. An implementation
of the visitor pattern just calls an accept() method
on the type_map_base templates wrapping each element,
with the default for no_typeN being empty. This
allows things like generic serialisation, assuming the
fields/members/elements are serialisable.

* You can enquire whether a particular type is in the
map (the T* find<T> implementation if/elses through
is_same<TN,T> tests, returning a pointer or 0).

* Removal of the redundant field-name + implicit-type
information inherent after evolving from the
type-unsafe:

    a_sname.first_m = x.get_last_name();

  to use of distinct types for fields, ensuring a
match such as:

    a_sname.last_m = x.get_last_name();

Cheers,

Tony

P.S. Hope the following (228 lines) aren't considered
excessive...

#include <typeinfo>
#include <boost/type_traits/is_same.hpp>

namespace NS
{

    namespace Private
    {
        class no_type1 { };
        class no_type2 { };
        class no_type3 { };
        class no_type4 { };

        template <typename T>
        class type_map_base
        {
          public:
            enum { COUNT = 1 };

            void operator=(const T& t) { t_ = t; }
            operator const T&() const { return t_; }

            template <class VISITOR>
            void accept(const VISITOR& visitor)
            {
                visitor.on_visit(t_);
            }

            T* get_ptr() { return &t_; }
            const T* get_ptr() const { return &t_; }

          private:
            T t_;
        };

        // have to explicitly incorporate
apply_functor to retain EBCO w/ g++
        template<> struct type_map_base<no_type1>
        {
            enum { COUNT = 0 };
            template <class V> inline void
accept(const V&) { }
            void* get_ptr() { return 0; }
        };

        template<> struct type_map_base<no_type2>
        {
            enum { COUNT = 0 };
            template <class V> inline void
accept(const V&) { }
            void* get_ptr() { return 0; }
        };

        template<> struct type_map_base<no_type3>
        {
            enum { COUNT = 0 };
            template <class V> inline void
accept(const V&) { }
            void* get_ptr() { return 0; }
        };

        template<> struct type_map_base<no_type4>
        {
            enum { COUNT = 0 };
            template <class V> inline void
accept(const V&) { }
            void* get_ptr() { return 0; }
        };
    }

    template <typename T0,
              typename T1 = Private::no_type1,
              typename T2 = Private::no_type2,
              typename T3 = Private::no_type3,
              typename T4 = Private::no_type4>
    class type_map : public
Private::type_map_base<T0>,
                     public
Private::type_map_base<T1>,
                     public
Private::type_map_base<T2>,
                     public
Private::type_map_base<T3>,
                     public Private::type_map_base<T4>
    {
      public:
        enum { COUNT =
Private::type_map_base<T0>::COUNT +
                      
Private::type_map_base<T1>::COUNT +
                      
Private::type_map_base<T2>::COUNT +
                      
Private::type_map_base<T3>::COUNT +
                      
Private::type_map_base<T4>::COUNT };

        typedef T0 type_1;
        typedef T1 type_2;
        typedef T2 type_3;
        typedef T3 type_4;
        typedef T4 type_5;

        template <typename VISITOR>
        void accept(const VISITOR& visitor)
        {
            visitor.on_before();
           
Private::type_map_base<T0>::accept(visitor);
            if (COUNT >= 2)
            {
                visitor.on_between();
               
Private::type_map_base<T1>::accept(visitor);

                if (COUNT >= 3)
                {
                    visitor.on_between();
                   
Private::type_map_base<T2>::accept(visitor);
                    if (COUNT >= 4)
                    {
                        visitor.on_between();
                       
Private::type_map_base<T3>::accept(visitor);
                        if (COUNT >= 5)
                        {
                            visitor.on_between();
                           
Private::type_map_base<T4>::accept(visitor);
                        }
                    }
                }
            }
            visitor.on_after();
        }

        // return pointer to member else NULL
        template <typename T>
        T* find()
        {
            if (boost::is_same<T, T0>::value)
                return
(T*)Private::type_map_base<T0>::get_ptr();
            else if (boost::is_same<T, T1>::value)
                return
(T*)Private::type_map_base<T1>::get_ptr();
            else if (boost::is_same<T, T2>::value)
                return
(T*)Private::type_map_base<T2>::get_ptr();
            else if (boost::is_same<T, T3>::value)
                return
(T*)Private::type_map_base<T3>::get_ptr();
            else if (boost::is_same<T, T4>::value)
                return
(T*)Private::type_map_base<T4>::get_ptr();
            else
                return 0;
        }

        template <int N>
        const std::type_info& ct_get_type_info() const
        {
            switch(N)
            {
              case 0: return typeid(T0);
              case 1: return typeid(T1);
              case 2: return typeid(T2);
              case 3: return typeid(T3);
              case 4: return typeid(T4);
              default: return typeid(void);
            }
        }

        const std::type_info& rt_get_type_info(int n)
const
        {
            switch(n)
            {
              case 0: return typeid(T0);
              case 1: return typeid(T1);
              case 2: return typeid(T2);
              case 3: return typeid(T3);
              case 4: return typeid(T4);
              default: return typeid(void);
            }
        }

        using Private::type_map_base<T0>::operator=;
        using Private::type_map_base<T1>::operator=;
        using Private::type_map_base<T2>::operator=;
        using Private::type_map_base<T3>::operator=;
        using Private::type_map_base<T4>::operator=;
    };
}

#include <iostream>
#include <string>

using namespace std;

class Printer
{
  public:
    void on_before() const
    {
        cout << "{ ";
    }

    template <typename T>
    void on_visit(const T& t) const
    {
        cout << t;
    }

    void on_between() const
    {
        cout << ", ";
    }

    void on_after() const
    {
        cout << " }" << endl;
    }
};

int main()
{
    NS::type_map<int, float, string> tmid;

    tmid = 3;
    tmid = (float)2.71828;
    tmid = "hello";
    string s = tmid;

    cout << "operator T(): " << (int)tmid << ' ' <<
(float)tmid << ' ' << s
         << endl;

    cout << "sizeof comparison: " << sizeof(tmid) << "
vs " << sizeof(int)
         << '+' << sizeof(float) << '+' <<
sizeof(string) << endl;

    cout << "::COUNT " << NS::type_map<int,
string>::COUNT << endl;

    cout << "Printing..." << endl;
    Printer printer;
    tmid.accept(printer);

    float* p_float = tmid.find<float>();
    cout << "p_float " << p_float << endl;

    double* p_double = tmid.find<double>();
    cout << "p_double " << p_double << endl;
}

                
___________________________________________________________
To help you stay safe and secure online, we've developed the all new Yahoo! Security Centre. http://uk.security.yahoo.com


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