|
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