Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using template metaprogramming to generate a composite class with ID derived from components

131 views
Skip to first unread message

Mikademus

unread,
May 4, 2005, 11:01:11 AM5/4/05
to
Given a set of classes

class A { enum {ID = 0x0001} };
class B { enum {ID = 0x0002} };
class B { enum {ID = 0x0004} };

I wish to generate a composite class, perhaps using something like
Alexandrescu's typelists

(pseudo-code:)

template<class TList>
class Composite : TList
{
enum {ID = SumID<TList>::result}
};

typedef composite<TYPELIST(A,B,C)> CompABC; // ID == 0x0007

Of course, the trivial A, B and C classes above would have data members
to make Composite meaningful, but the really important issue is
Composite's ID member, the value of which must be unique to the
combinations of components.

Thus, there are two parts to this. One, generating a linear inheritance
hierarchy from the typelist; and two, summing up the components' ID
values as the ID value of the generated composite.

Though I know exactly what I need I've so far (due to my inexperience
with metaprogramming) failed to implement this. I've tried using
Alexandrescu's Loki and BoostMPL, but am stymied. Any help would be
deeply appreciated!


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Andrei Alexandrescu (See Website For Email)

unread,
May 4, 2005, 8:00:13 PM5/4/05
to
Mikademus wrote:
> Given a set of classes
>
> class A { enum {ID = 0x0001} };
> class B { enum {ID = 0x0002} };
> class B { enum {ID = 0x0004} };
>
> I wish to generate a composite class, perhaps using something like
> Alexandrescu's typelists
>
> (pseudo-code:)
>
> template<class TList>
> class Composite : TList
> {
> enum {ID = SumID<TList>::result}
> };
>
> typedef composite<TYPELIST(A,B,C)> CompABC; // ID == 0x0007

template <class TList> struct Composite {
enum{ID = 0};
};

template <class H, class T>
struct Composite< Typelist<H, T> > {
enum {ID = H::ID + Composite<T>::ID};
};


Andrei

Larry Evans

unread,
May 4, 2005, 7:58:50 PM5/4/05
to
On 05/04/2005 10:01 AM, Mikademus wrote:
> Given a set of classes
>
> class A { enum {ID = 0x0001} };
> class B { enum {ID = 0x0002} };
> class B { enum {ID = 0x0004} };
>
> I wish to generate a composite class, perhaps using something like
> Alexandrescu's typelists
>
> (pseudo-code:)
>
> template<class TList>
> class Composite : TList
> {
> enum {ID = SumID<TList>::result}
> };
>
> typedef composite<TYPELIST(A,B,C)> CompABC; // ID == 0x0007
>
> Of course, the trivial A, B and C classes above would have data members
> to make Composite meaningful, but the really important issue is
> Composite's ID member, the value of which must be unique to the
> combinations of components.
>
> Thus, there are two parts to this. One, generating a linear inheritance
> hierarchy from the typelist; and two, summing up the components' ID
> values as the ID value of the generated composite.
>
> Though I know exactly what I need I've so far (due to my inexperience
> with metaprogramming) failed to implement this. I've tried using
> Alexandrescu's Loki and BoostMPL, but am stymied. Any help would be
> deeply appreciated!

You could use boost::mpl::fold to sum the ID's of the component types,
and use it again to create the composite type:

template<class TList>
: public mpl::fold
< TList
, mpl::empty_base
, inherit_left<_1,_2>
>::type
{
enum
{ ID=mpl::fold
< TList
, mpl::integral_c<0>
, partial_sum<_2,_1>
>::type::value
};
};

where:

template<class L,class R>
struct partial_sum
: mpl::integral_c<int,L::ID+R::value>
{
typedef partial_product type;
};

and inherit_left is the same as in:

http://boost-sandbox.sourceforge.net/vault/index.php?&direction=0&order=&directory=cppljevans/mpl

in file fold_seq_test.zip in the .cpp file. The partial_sum is just the
partial_product template class in that same file, but with + instead of
* as the operator, and with the left argument being, in your case,
class A,B or C.

BTW, I didn't test this, so don't be surprised if it needs tweaking.

HTH.

David Abrahams

unread,
May 4, 2005, 8:14:06 PM5/4/05
to
Mikademus <mika...@home.se> writes:

> Given a set of classes
>
> class A { enum {ID = 0x0001} };
> class B { enum {ID = 0x0002} };
> class B { enum {ID = 0x0004} };
>
> I wish to generate a composite class, perhaps using something like
> Alexandrescu's typelists
>
> (pseudo-code:)
>
> template<class TList>
> class Composite : TList
> {
> enum {ID = SumID<TList>::result}
> };
>
> typedef composite<TYPELIST(A,B,C)> CompABC; // ID == 0x0007
>
> Of course, the trivial A, B and C classes above would have data members
> to make Composite meaningful, but the really important issue is
> Composite's ID member, the value of which must be unique to the
> combinations of components.

#include <boost/mpl/int.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/plus.hpp>

namespace mpl = boost::mpl;

template <class T>
struct get_id
{
typedef mpl::int_<T::ID> type;
};

template <class Types>
struct composite
{
enum {ID = mpl::fold<
Types
, mpl::int_<0>
, mpl::plus<_1, get_id<_2> >
>::type::value
};
};

composite<mpl::vector<A,B,C> > x;

> Thus, there are two parts to this. One, generating a linear
> inheritance hierarchy from the typelist;

You really want the linear inheritance hierarchy too? Well OK, then
use this version of composite:

#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/inherit.hpp>

template <class Types>
struct composite
: mpl::inherit_linearly<Types, mpl::inherit<_,_> >::type
{
enum {ID = mpl::fold<
Types
, mpl::int_<0>
, mpl::plus<_1, get_id<_2> >
>::type::value
};
};

> and two, summing up the components' ID
> values as the ID value of the generated composite.
>
> Though I know exactly what I need I've so far (due to my
> inexperience with metaprogramming) failed to implement this. I've
> tried using Alexandrescu's Loki and BoostMPL, but am stymied. Any
> help would be deeply appreciated!

HTH,
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Carl Barron

unread,
May 5, 2005, 7:10:44 AM5/5/05
to
In article <usm126...@boost-consulting.com>, David Abrahams
<da...@boost-consulting.com> wrote:

> #include <boost/mpl/int.hpp>
> #include <boost/mpl/fold.hpp>
> #include <boost/mpl/plus.hpp>
>

Does linear_hierarchy<vector<a,b,c> > really generate a linear
hierarchy like:
a->A->b->B->c
and not a ->{a,b,c}
a->is a base class o and {} is ->{} is a base class of all the classes
like the straws on a broom?

in other words what is the easiest way to emulate Loki::ScatterHierarchy
and Loki::LinearHierarchy in mpl???

Carl Barron

unread,
May 5, 2005, 7:07:25 AM5/5/05
to
In article <4278B6F7...@home.se>, Mikademus <mika...@home.se>
wrote:

> Given a set of classes
>
> class A { enum {ID = 0x0001} };
> class B { enum {ID = 0x0002} };
> class B { enum {ID = 0x0004} };
>
> I wish to generate a composite class, perhaps using something like
> Alexandrescu's typelists
>
> (pseudo-code:)
>
> template<class TList>
> class Composite : TList
> {
> enum {ID = SumID<TList>::result}
> };
>
> typedef composite<TYPELIST(A,B,C)> CompABC; // ID == 0x0007
>
> Of course, the trivial A, B and C classes above would have data members
> to make Composite meaningful, but the really important issue is
> Composite's ID member, the value of which must be unique to the
> combinations of components.
>
> Thus, there are two parts to this. One, generating a linear inheritance
> hierarchy from the typelist; and two, summing up the components' ID
> values as the ID value of the generated composite.
>
> Though I know exactly what I need I've so far (due to my inexperience
> with metaprogramming) failed to implement this. I've tried using
> Alexandrescu's Loki and BoostMPL, but am stymied. Any help would be
> deeply appreciated!
>

using namespace Loki;
typedef Int2Type<1> A;
typedef Int2Type<2> B;
typedef Int2Type<4> C;

template <class T> struct OrValues;

template <classs H,class T> struct OrValues<Typelist<H,T> >
:Int2Type< A::Value | OrValues<T>::Value >{};

template <> struct OrValues<NullType>::Int2Type<0>{};

typedef OrValues<A,B,C> ans;//ans.Value == 7

using boost::mpl

typedef int_<1> A;
typedef int_<2> B;
typedef int_<4> C;

template <class Seq> struct OrValues:fold<Seq,int_<0>,_1 |
_2>::type{};

typedef OrValues<vector<A,B,C> > ans ;// ans::value == 7

Larry Evans

unread,
May 5, 2005, 8:48:06 AM5/5/05
to
On 05/04/2005 06:58 PM, Larry Evans wrote:
[snip]

> You could use boost::mpl::fold to sum the ID's of the component types,
> and use it again to create the composite type:
>
> template<class TList>
> : public mpl::fold
> < TList
> , mpl::empty_base
> , inherit_left<_1,_2>
^^^^^^^^^^^^
after reading David's reply, I realized this should be inherit instead
of inherit_left. This is needed to *inherit* from the components
in TList instead of create a *tuple* from them.

David Abrahams

unread,
May 6, 2005, 3:51:41 AM5/6/05
to
Carl Barron <cbarr...@adelphia.net> writes:

> In article <usm126...@boost-consulting.com>, David Abrahams
> <da...@boost-consulting.com> wrote:
>
>
>
>> #include <boost/mpl/int.hpp>
>> #include <boost/mpl/fold.hpp>
>> #include <boost/mpl/plus.hpp>
>>
> Does linear_hierarchy<vector<a,b,c> > really generate a linear
> hierarchy like:
> a->A->b->B->c
> and not a ->{a,b,c}
> a->is a base class o and {} is ->{} is a base class of all the classes
> like the straws on a broom?
>
> in other words what is the easiest way to emulate Loki::ScatterHierarchy
> and Loki::LinearHierarchy in mpl???

Loki::GenScatterHierarchy is somewhat misleadingly named; it always
generates inheritance of the form:

*
/ \
@ *
/ \
@ *
/ \
@ *
/ \
@ X

Pretty linear, really. That's what the example I posted does, where
every '*' is a specialization of mpl::inherit<T,U> and every @ is an
element of the input sequence.

Loki::GenLinearHierarchy relies on being passed a class template whose
2nd argument specifies its base class. I don't like the design very
much: it gets specializations of GenLinearHierarchy itself mixed into
the generated type. That adds nothing useful and complicates the
resulting type (GenScatterHierarchy has the same problem actually).
The essence of what GenLinearHierarchy does is to turn a sequence S
of types:

T1, T2, T3... TN

a combiner template

template <class T, class Base>
struct unit : Base { ... };

and some root type

Root

into

unit<T1,
unit<T2,
unit<T3, ...
unit<TN, Root>
...
>
>
>

That's just

mpl::reverse_fold<S, Root, unit<_2,_1> >::type

I just used reverse_fold so that unit<T1, ...> would be the outer
type, as shown. If order doesn't matter, fold would work just fine.

HTH,
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Mikademus

unread,
May 6, 2005, 6:21:13 AM5/6/05
to
(Original post attached at the end)

Everyone who answered, thank you very much! Your code, hints and
directions, especially in making me closely examine the boost::mpl, was
to tremendous help!

By using the code in Andrei's reply and figuring out the inheritance
pattern from boost::mpl::inherit (and that was not easy - that have got
to be some of the most cryptic source I've ever read!) I think I've
managed to find a sufficient (and dare I say quite aesthetic?) solution
using Loki's typelists and NullType:

struct A
{
enum {ID = 0x0001};
__int8 dummy1;
};

struct B
{
enum {ID = 0x0002};
__int16 dummy2;
};

struct C
{
enum {ID = 0x0004};
__int32 dummy3;
};


template<class TList> struct Composite

: TList::Head, Composite<typename TList::Tail>
{
enum {ID = TList::Head::ID
+ Composite<typename TList::Tail>::ID};
};

template<> struct Composite<NullType>
{
enum{ID = 0};
};


int main()
{
using namespace std;

Composite<TYPELIST_3(A,B,C)> my_composite;

return 0;
}


Remaining issues in the code above:

* Components should be sorted ascending by ID
* Multiple inclusions of same type should removed

But these are minor issues and Loki comes furbished with the
facitilites
for taking care of both. Since the solution above is quite simpler than
the ones using Boost I got in reply I suspect I might have
misunderstood
and/or miused the term "linear inheritence", if so I apologise. If you
see any flaws in my solution I would be grateful if you pointed these
out.

Regards,
Mikael Andersson


> Given a set of classes
>
> class A { enum {ID = 0x0001} };
> class B { enum {ID = 0x0002} };

> class C { enum {ID = 0x0004} };


>
> I wish to generate a composite class, perhaps using something like
Alexandrescu's typelists
>
> (pseudo-code:)
>
> template<class TList>
> class Composite : TList
> {
> enum {ID = SumID<TList>::result}
> };
>

> typedef Composite<TYPELIST(A,B,C)> CompABC; // ID == 0x0007

0 new messages