Hi all,
I'm new to using the MPL and I want to write a generic class, that
makes it easy to provide other classes with a mechanism to notify
their clients about member changes. I'll paste in some code that
illustrates how I imagine this thing could look like. I've marked
three places with comments ((1), (2), (3)) that contain the specific
questions but I also welcome more general suggestions. For example
I'd appreciate alternatives to the std::map within the Notifier.
<code>
template
class Notifier
{
// an alternative combiner for signals
struct notifier_combiner
{
typedef boost::optional< int > result_type;
template <typename INPUT_ITERATOR>
result_type operator()(INPUT_ITERATOR pFirst, INPUT_ITERATOR pLast) const
{
result_type res;
for (; pFirst != pLast; ++pFirst)
res = *pFirst;
return res;
}
};
template
struct get_signal_type
{
typedef boost::signal< int (OBJECT_TYPE const*, MEMBER_TYPE const&), notifier_combiner > type;
};
// (1) How can I get SOMETHING? It should be a sequence of all
// possible signal types, most probably an mpl::set, so that each
// signal type is only present once. I guess I should iterate
// over the elements in ID_TO_MEMBER_MAP_TYPE and then call
// get_signal_type< elem::first::value, elem::second::type >, but
// I don't see exactly how to use one of the mpl-algorithms or
// generic iteration.
typedef boost::make_variant_over< SOMETHING >::type signals_t;
// maps member ids to a variant containing the 'right' signal type
typedef std::map< MEMBER_ID_TYPE, signals_t > signal_map_t;
signal_map_t signal_map;
public:
Notifier()
{
// (2) How do I initialise signal_map so that all ids map to a
// signals_t instance with the right default constructed
// signal type assigned? I guess the answer is somewhere in
// chapter 9 of "C++ template metaprogramming" but that's the
// chapter that is the hardest one to grasp for me :-)
}
template
boost::connection connect(get_signal_type< id, MEMBER_TYPE >::type::slot_type slot)
{
return boost::get< get_signal_type< id, MEMBER_TYPE >::type >(signal_map[id]).connect(slot);
}
template
int notify(OBJECT_TYPE const *pObj, MEMBER_TYPE const &member_val) const
{
boost::optional< int > res = boost::get< get_signal_type< id, MEMBER_TYPE >::type >(signal_map[id])(pObj, member_val);
return res ? res.get() : 0;
}
};
// how I'd like to use it:
strcut sth_
{
int i;
long j;
}
class RandomClass
{
bool yesno;
sth_ sth;
enum MemberId
{
YESNO
, STH
};
typedef mpl::map<
mpl::pair< mpl::integral_c< MemberId, YESNO >, bool >
, mpl::pair< mpl::integral_c< MemberId, STH >, sth_ >
> id_to_member_type_t;
template < typename INTEGRAL_CONST >
struct get_type_by_id
{
typedef mpl::at< id_to_member_type_t, INTEGRAL_CONST >::type type;
};
Notifier< RandomClass // I hope incomplete type is ok here
// (because Notifier only uses
// RandomClass const*; OTOH, Notifier
// uses a std::map which somehow
// refers to RandomClass)? Anyway,
// this is not crucial.
, MemberId
, mpl::map<
mpl::pair< mpl::integral_c< MemberId, YESNO >, bool >
, mpl::pair< mpl::integral_c< MemberId, YESNO >, sth_ >
>
> m_notifier;
public:
RandomClass()
: yesno(false)
, sth({1, 2})
{
}
// a client connects by specifying the member id and a callback
template < MemberId id >
boost::connection notify(int (pF*)(RandomClass const*
, get_type_by_id<
mpl::integral_c< MemberId, id >
>::type const&))
{
// (3) Can the compiler deduce the second template argument of
// Notifier::connect? I guess not, so how could I change the
// method's declaration to make that happen?
return m_notifier.connect< id >(pF);
}
void setYesNo(bool b)
{
yesno = b;
m_notifier<YESNO>(this, b);
}
void setSthI(int i)
{
sth.i = i;
m_notifier<STH>(this, sth);
}
};
</code>
Obviously this doesn't yet compile and there may be all sorts of
errors. I hope that's ok, because I still need very basic help.
TIA,
aa
--
Andreas Ames | Programmer | Comergo GmbH |
Voice: +49 69 7505 3213 | andreas . ames AT comergo . com
"I imagine Sisiphus as happy ..." Albert Camus