C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Type erasure through meta-program?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Gino van den Bergen
Guest





PostPosted: Tue Nov 22, 2005 7:35 pm    Post subject: Type erasure through meta-program? Reply with quote



Hi,

I have a class template of the form

template <unsigned char FLAGS>
class Foo : public Bar
{
// blah
};

Bar is an interface class (pure virtual member functions only). For
constructing objects of type Foo<FLAGS> I use a create function template:

template <unsigned char FLAGS>
Bar* createFoo()
{
return new Foo<FLAGS>();
}

Now, I want to offer a C-API for creating these objects and thus need to
perform a form of type erasure:

BarHandle apiCreateFoo(unsigned char flags);

Here, "flags" is a run-time variable instead of a template argument. One
way to implement this function is


BarHandle apiCreateFoo(unsigned char flags)
{
typedef Bar* (*CreateFunc)();
static CreateFunc createFunc[256] = {
&createFoo<0>,
&createFoo<1>,
...
&createFoo<255>
};

return reinterpret_cast<BarHandle>((*createFunc[flags])());
}

I need to do this for a number of different class templates.

My question is: Is there way to perform the type erasure automagically
without resorting to copy-paste?

I can think of a number of solutions.

(1) Create a header file that uses a macro for each entry in the list of
CreateFuncs. By including this header file multiple times, each time
using a different definition of the macro I can generate a static array
of creation functions for each class template.

(2) Use a singleton factory class template

template <typename T>
class CreationList
{
public:
static CreationList* instance();
Bar* create(unsigned char flags);
protected:
CreationList();

private:
CreateFunc m_createFunc[256];
};

Here, the constructor performs a hard-coded initialization of
m_createFunc for type T.

(3) Through meta-programming? I was thinking in the direction of
generalized abstract factories as described in Alexandrescu's Modern C++
Design. You could generate an object that holds all createFuncs and
treat this object as an array (possibly through some dirty casting). One
concern I have with this method is that C++ compilers may have trouble
handling recursion depths of 256.


NB: Not all flag values are valid, so if I need to hard-code the array
initialization then I can leave out instances for certain flags values.
Saving up code memory and enabling early error handling.

What do you consider to be the best method for erasing the template types?

Gino


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

Back to top
Maxim Yegorushkin
Guest





PostPosted: Wed Nov 23, 2005 3:06 pm    Post subject: Re: Type erasure through meta-program? Reply with quote




Gino van den Bergen wrote:
Quote:
Hi,

I have a class template of the form

template <unsigned char FLAGS
class Foo : public Bar
{
// blah
};

Bar is an interface class (pure virtual member functions only). For
constructing objects of type Foo
template <unsigned char FLAGS
Bar* createFoo()
{
return new Foo }

Note, that this function actually performs type erasure, after you get
a Bar* the type erasure work is done.

Quote:
Now, I want to offer a C-API for creating these objects and thus need to
perform a form of type erasure:

BarHandle apiCreateFoo(unsigned char flags);

Here, "flags" is a run-time variable instead of a template argument. One
way to implement this function is


BarHandle apiCreateFoo(unsigned char flags)
{
typedef Bar* (*CreateFunc)();
static CreateFunc createFunc[256] = {
&createFoo<0>,
&createFoo<1>,
...
&createFoo<255
};

return reinterpret_cast }

I need to do this for a number of different class templates.

My question is: Is there way to perform the type erasure automagically
without resorting to copy-paste?

This is not a type erasure problem, rather the problem of generating an
array of pointers to functions.

You can use boost::mpl for generating the array. Note that the
generation happens at run-time, while using macros you can hardcode the
array. Here is a sketch:

#include <iostream>

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/iterator_range.hpp>
#include <boost/mpl/int.hpp>

namespace mpl = boost::mpl;

template<int N>
void* foo()
{
std::cout << N << 'n';
return 0;
}

void*(*foos[256])(); // the array

void bar(int n)
{
foos[n]();
}

struct gen_foo_ftor
{
template void operator()(mpl::int_<N>)
{
foos[N] = foo<N>;
}
};

void gen_foos() // the array generator
{
mpl::for_each<
mpl::iterator_range
Quote:
(gen_foo_ftor());
}


int main()
{
gen_foos();
for(int n = 0; n != 0x100; ++n)
bar(n);
}


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


Back to top
Martin Eisenberg
Guest





PostPosted: Wed Nov 23, 2005 5:42 pm    Post subject: Re: Type erasure through meta-program? Reply with quote



Gino van den Bergen wrote:

Quote:
(3) Through meta-programming? I was thinking in the direction of
generalized abstract factories as described in Alexandrescu's
Modern C++ Design. You could generate an object that holds all
createFuncs and treat this object as an array (possibly through
some dirty casting). One concern I have with this method is that
C++ compilers may have trouble handling recursion depths of 256.

With a branching recursion, you only need depth 8.


Martin

--
Quidquid latine scriptum sit, altum viditur.

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


Back to top
Gino van den Bergen
Guest





PostPosted: Thu Dec 01, 2005 3:40 pm    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

Maxim Yegorushkin wrote:
Quote:
Gino van den Bergen wrote:

Hi,

I have a class template of the form

template <unsigned char FLAGS
class Foo : public Bar
{
// blah
};

Bar is an interface class (pure virtual member functions only). For
constructing objects of type Foo
template <unsigned char FLAGS
Bar* createFoo()
{
return new Foo }


Note, that this function actually performs type erasure, after you get
a Bar* the type erasure work is done.


Now, I want to offer a C-API for creating these objects and thus need to
perform a form of type erasure:

BarHandle apiCreateFoo(unsigned char flags);

Here, "flags" is a run-time variable instead of a template argument. One
way to implement this function is


BarHandle apiCreateFoo(unsigned char flags)
{
typedef Bar* (*CreateFunc)();
static CreateFunc createFunc[256] = {
&createFoo<0>,
&createFoo<1>,
...
&createFoo<255
};

return reinterpret_cast }

I need to do this for a number of different class templates.

My question is: Is there way to perform the type erasure automagically
without resorting to copy-paste?



Thanks for your responses!

I've decided to create a class template for creating singleton arrays
storing 256 different intances of the Foo creation function template. I
instance this singleton class template for a small number (currently 6)
types.

The "Foo" template here, uses the unsigned char as a bitfield for
selecting different capabilities (policies/strategie, you name it), so
there is some mild meta-programming done for each instance of "Foo".

On Visual C++ 7.1 and 8.0 compilation takes close to a minute for
creating all singleton instances and creates an optimized binary of
roughly 500K. Under g++ 4.0 however, compilation takes close to half an
hour (!!) and results in an optimized binary of 5MB (an order of
magnitude larger).

Can anyone here explain the difference in performance between the two
compilers? Are there any compiler flags I can use with g++ to speed up
compilation / reduce code size?

Thanks,

Gino


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


Back to top
David Abrahams
Guest





PostPosted: Fri Dec 02, 2005 12:38 am    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:

Quote:
On Visual C++ 7.1 and 8.0 compilation takes close to a minute for
creating all singleton instances and creates an optimized binary of
roughly 500K. Under g++ 4.0 however, compilation takes close to half an
hour (!!) and results in an optimized binary of 5MB (an order of
magnitude larger).

Can anyone here explain the difference in performance between the two
compilers? Are there any compiler flags I can use with g++ to speed up
compilation / reduce code size?

Try turning off debug info :)

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

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


Back to top
Gino van den Bergen
Guest





PostPosted: Fri Dec 02, 2005 5:22 pm    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

David Abrahams wrote:

Quote:
Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:



On Visual C++ 7.1 and 8.0 compilation takes close to a minute for
creating all singleton instances and creates an optimized binary of
roughly 500K. Under g++ 4.0 however, compilation takes close to half an
hour (!!) and results in an optimized binary of 5MB (an order of
magnitude larger).

Can anyone here explain the difference in performance between the two
compilers? Are there any compiler flags I can use with g++ to speed up
compilation / reduce code size?



Try turning off debug info :)



The 5MB binary *is* the stripped release version. The debug binary is
over 11MB :(

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


Back to top
David Abrahams
Guest





PostPosted: Sat Dec 03, 2005 1:41 am    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:

Quote:
David Abrahams wrote:

Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:



On Visual C++ 7.1 and 8.0 compilation takes close to a minute for
creating all singleton instances and creates an optimized binary of
roughly 500K. Under g++ 4.0 however, compilation takes close to half an
hour (!!) and results in an optimized binary of 5MB (an order of
magnitude larger).

Can anyone here explain the difference in performance between the two
compilers? Are there any compiler flags I can use with g++ to speed up
compilation / reduce code size?



Try turning off debug info :)



The 5MB binary *is* the stripped release version. The debug binary is
over 11MB Sad

In that case I suggest you look for compile-time inefficiencies.

You might find Appendix C of http://www.boost-consulting.com/mplbook
useful ;-)

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

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


Back to top
Gino van den Bergen
Guest





PostPosted: Tue Dec 06, 2005 11:26 am    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

David Abrahams wrote:
Quote:
Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:


David Abrahams wrote:


Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:



On Visual C++ 7.1 and 8.0 compilation takes close to a minute for
creating all singleton instances and creates an optimized binary of
roughly 500K. Under g++ 4.0 however, compilation takes close to half an
hour (!!) and results in an optimized binary of 5MB (an order of
magnitude larger).

Can anyone here explain the difference in performance between the two
compilers? Are there any compiler flags I can use with g++ to speed up
compilation / reduce code size?


Try turning off debug info :)



The 5MB binary *is* the stripped release version. The debug binary is
over 11MB :(


In that case I suggest you look for compile-time inefficiencies.

You might find Appendix C of http://www.boost-consulting.com/mplbook
useful ;-)



Your book (which btw has been a great help in getting this far) only
partly explains the difference in performance between the two compiler
series. What I cannot figure out is why the g++ compiler generates
roughly ten times as much object code than the Visual C++ compiler. Let
me explain more closely what I'm trying to do:

I use the following template to construct a transform object based on
certain properties determined by FLAGS.

template <unsigned char FLAGS>
struct TransformBuilder
{
typedef typename If<(FLAGS & DT_SCALE) != 0,
Scale, TransformBase>::Result_type S;
typedef typename If<(FLAGS & DT_SCALEORIENT) != 0,
ScaleOrientation, S>::Result_type SR;
typedef typename If<(FLAGS & DT_ORIENTATION) != 0,
Orientation::Result_type OSR;
typedef typename If<(FLAGS & DT_ROTATION) != 0,
Rotation::Result_type RSR;
typedef typename If<(FLAGS & DT_POSITION) != 0,
Position::Result_type PRSR;
typedef typename If<(FLAGS & DT_TRANSLATION) != 0,
Translation::Result_type TRSR;
typedef typename If<(FLAGS & DT_CENTER) != 0,
Center::Result_type CTRSR;
typedef typename If<(FLAGS & DT_DILATION) != 0,
Dilation::Result_type Result_type;
};


Here, the "If" template is defined by


template <bool, typename Positive, typename Negative>
struct If
{
typedef Positive Result_type;
};

template <typename Positive, typename Negative>
struct If<false, Positive, Negative>
{
typedef Negative Result_type;
};


Next, I generate a transform object through


template <Flags_t FLAGS = 0>
class Transform
: public TransformBuilder<FLAGS>::Result_type
{
// transform operations
};

These are used in the following template for constructing transformed
objects:

template <typename Base, Flags_t FLAGS = 0>
class Convex
: public Base
, public Transform<FLAGS>
{
// object operations
};

Finally, I perform type erasure through a wrapper template

template <typename Convex>
class ConvexWrapper
: public Object
{
public:
// virtual function declarations.

private:
Convex m_convex;
}

Here, "Object" is an interface class (pure virtuals).

I create objects through the following creation function

template <Flags_t FLAGS, typename Base>
Object* createConvex(const Base& base)
{
return new ConvexWrapper<Convex(Convex<Base,
FLAGS>(base));
}


Finally, I use a singleton object factory for creating all instances at
run-time

template <typename Base>
class ObjectFactory
{
public:
static ObjectFactory<Base>* instance()
{
static ObjectFactory<Base> g_factory;
return &g_factory;
}

Object* create(DtFlags flags, const Base& base)
{
if (m_createFuncs[flags] == 0)
{
throw DT_INVALID_PARAMETER;
}
return (*m_createFuncs[flags])(base);
}

protected:
ObjectFactory()
{
m_createFuncs[0] = &createConvex<0, Base>;
m_createFuncs[DT_SCALE] = &createConvex<DT_SCALE, Base>;

//...etc, for all valid flags (max 256).
}
private:
typedef Object* (*CreateFunc)(const Base& base);

CreateFunc m_createFuncs[256];
};



As you can see there is not a lot of deep meta-programming going on, so
why is it possible that there is such a big difference in executable
code sizes between the two compilers?

Gino

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


Back to top
David Abrahams
Guest





PostPosted: Tue Dec 06, 2005 1:13 pm    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:

Quote:
As you can see there is not a lot of deep meta-programming going on, so
why is it possible that there is such a big difference in executable
code sizes between the two compilers?

There's also a lot of non-metaprogramming, i.e. ordinary runtime code
involved there. Executable size usually has a direct relationship to
things that show up in a link map: virtual tables, non-inlined
functions, globals, etc. It seems highly unlikely that any size
you're seeing there has much to do with compile-time mechanics.

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

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


Back to top
Gino van den Bergen
Guest





PostPosted: Wed Dec 07, 2005 6:49 pm    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

David Abrahams wrote:
Quote:
Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:


As you can see there is not a lot of deep meta-programming going on, so
why is it possible that there is such a big difference in executable
code sizes between the two compilers?


There's also a lot of non-metaprogramming, i.e. ordinary runtime code
involved there. Executable size usually has a direct relationship to
things that show up in a link map: virtual tables, non-inlined
functions, globals, etc. It seems highly unlikely that any size
you're seeing there has much to do with compile-time mechanics.


I should add that I'm comparing the size of the stripped and optimized
DLL under Visual C++ against the size of the stripped and optimized
shared object under Linux. I'm using libtool to build the shared object
under Linux and limit the set of exported symbols to the same set of API
entries through the -export-symbols-regex option. I noticed that the
sizes of the static libs does not differ a lot (roughtly 15MB both). So,
probably it's a linker issue. Still the differences in compile times is
remarkable.


Gino

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


Back to top
David Abrahams
Guest





PostPosted: Thu Dec 08, 2005 11:57 am    Post subject: Re: Type erasure through meta-program? slow compilation usin Reply with quote

Gino van den Bergen <gino (AT) dtecta (DOT) COMEAGAIN> writes:

Quote:
I should add that I'm comparing the size of the stripped and
optimized DLL under Visual C++ against the size of the stripped and
optimized shared object under Linux. I'm using libtool to build the
shared object under Linux and limit the set of exported symbols to
the same set of API entries through the -export-symbols-regex
option.

Hmm, that eliminates the other obvious explanation.

Quote:
I noticed that the sizes of the static libs does not differ
a lot (roughtly 15MB both). So, probably it's a linker issue. Still
the differences in compile times is remarkable.

That could of course be accounted for by the cost of generating
whatever all that extra size accounts for. I'd be interested to know
what it turns out to be, when you find out!

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

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


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.