 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Gino van den Bergen Guest
|
Posted: Tue Nov 22, 2005 7:35 pm Post subject: Type erasure through meta-program? |
|
|
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
|
Posted: Wed Nov 23, 2005 3:06 pm Post subject: Re: Type erasure through meta-program? |
|
|
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
|
Posted: Wed Nov 23, 2005 5:42 pm Post subject: Re: Type erasure through meta-program? |
|
|
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
|
Posted: Thu Dec 01, 2005 3:40 pm Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
Posted: Fri Dec 02, 2005 12:38 am Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
Posted: Fri Dec 02, 2005 5:22 pm Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
Posted: Sat Dec 03, 2005 1:41 am Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
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
|
Posted: Tue Dec 06, 2005 11:26 am Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
Posted: Tue Dec 06, 2005 1:13 pm Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
Posted: Wed Dec 07, 2005 6:49 pm Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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
|
Posted: Thu Dec 08, 2005 11:57 am Post subject: Re: Type erasure through meta-program? slow compilation usin |
|
|
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 |
|
 |
|
|
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
|
|