Sign in to follow this  
mfawcett

template class creation from run-time info

Recommended Posts

I have a template class that takes a number of bools e.g. template <bool AlphaFunc, bool BlendFunc, bool TextureBind, bool CullFace, bool DepthFunc, bool DepthMask, bool ColorMask, bool StencilFunc, bool StencilMask, bool StencilOp> class material { /* etc */ }; Here is a link to the actual implementation. I save on space by only creating storage for the options that are used. This has worked great when all of my materials are created at compile-time, but now I'm supporting run-time creation with the materials stored in file. I can't think of a way to dynamically create the material class when the options are not known until run-time. I'm open to design suggestions as well as solutions to this problem. The design would (hopefully) eliminate wasted space for unused options and retain type info.

Share this post


Link to post
Share on other sites
You [afaik] can't. Templates are, by definition, compile time beasts only. No amount of black magic will allow you to specify the parameters at run time, only pick one that's already been created.

Share this post


Link to post
Share on other sites
Quote:
Original post by Telastyn
You [afaik] can't. Templates are, by definition, compile time beasts only. No amount of black magic will allow you to specify the parameters at run time, only pick one that's already been created.

I know that. It's not a problem for classes taking few template arguments, however this one takes 10. If I want to allow the user any combination of arguments, that is a hellof a lot of specializations to do.

For instance, with a much easier class: (this was typed in post, not compiled or tested)

if (token == "true")
{
ref.reset(new material<true>);
// Load options
}



but the problem grows HUGE with more template parameters. I don't even want a meta-program to generate it for me because it would explode compile times.

[Edited by - mfawcett on August 31, 2005 5:19:51 PM]

Share this post


Link to post
Share on other sites
Store a pointer to each one and make it null if that attribute is not required.

We're talking a maximum of 40 unused bytes here.

A single 256*256 RGBA texture = 262144 bytes

So in the space needed to store 1 modest sized texture you could store 6553 materials.

Presumably you'd be attaching a texture to each material. Why are you worried about possibly wasting 40 bytes? Even if all your materials were known at compile time, you're still heavily abusing the type system, which will cause problems later, for non real benefit.


Share this post


Link to post
Share on other sites
Quote:
Original post by mfawcett
I can't think of a way to dynamically create the material class when the options are not known until run-time. I'm open to design suggestions as well as solutions to this problem.

The design would (hopefully) eliminate wasted space for unused options and retain type info.


One way to do it at run-time might be to have pointers in the material class pointing to the various data allocated elsewhere. Pointers for disabled features would be 0.

The real question is this: How much wasted space do you expect to eliminate? Even with 1000 materials, you are going to save less than 100 Kbytes. Is it even worth all the effort?

Share this post


Link to post
Share on other sites
Well, with 10 boolean options that gives you 2^10=1024 possible combinations, which not only gives you 1024 different structures it also means all the code that uses them will need to be duplicated 1024 times unless you use virtual functions (which I think would be a very bad idea here). So you can either use pointers to each material type (but remember memory allocation overhead, which is ~8 bytes per alloc for a good allocator), or just stick all the properties into one big class and have a bit mask to indicate valid ones since none of them are that big anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nitage
Presumably you'd be attaching a texture to each material. Why are you worried about possibly wasting 40 bytes? Even if all your materials were known at compile time, you're still heavily abusing the type system, which will cause problems later, for non real benefit.

(The class I linked to has since been changed, but in actuality it ranged from 4 to 74 bytes.)

I've considered not worrying about the space, and will probably go with a run-time version of the class.

Quote:
Original post by ZQJ
Well, with 10 boolean options that gives you 2^10=1024 possible combinations, which not only gives you 1024 different structures it also means all the code that uses them will need to be duplicated 1024 times unless you use virtual functions (which I think would be a very bad idea here). So you can either use pointers to each material type (but remember memory allocation overhead, which is ~8 bytes per alloc for a good allocator), or just stick all the properties into one big class and have a bit mask to indicate valid ones since none of them are that big anyway.

I had gotten around that particular problem you mentioned, but yes, it does make working with the material a bit of a pain.

Basically:

template <bool>
struct uses_alpha_func
{
template <typename T>
void apply(const T &) const { }
};


template <>
struct uses_alpha_func<true>
{
template <typename T>
void apply(const T &a) const
{
glAlphaFunc(a.af_func, a.af_ref);
}
};


Share this post


Link to post
Share on other sites
That's still going to cause code duplication isn't it? Since you'll have to have one set of code that calls the <true> version and one that calls the <false> version. That is, if I understand what you're doing.

Share this post


Link to post
Share on other sites
Quote:
Original post by ZQJ
That's still going to cause code duplication isn't it? Since you'll have to have one set of code that calls the <true> version and one that calls the <false> version. That is, if I understand what you're doing.

Oh yea, definitely. I was just saying the programmer didn't actually have to do the duplication, the compiler could.

Share this post


Link to post
Share on other sites
I muat be being stupid BUT why are u declaring so many bools in your template when you just have to declare 1?

What are trying to achiveve? The whole point of templates is RUNTIME so you didn't have to do that when you knew how muany you'd ned at comille time. If you have veridiac runtime argumentents with tempaltes then Fruny is THE MAN...or you could just use the standard sytanx.?

Share this post


Link to post
Share on other sites
Quote:
Original post by garyfletcher
I muat be being stupid BUT why are u declaring so many bools in your template when you just have to declare 1?

What are trying to achiveve? The whole point of templates is RUNTIME so you didn't have to do that when you knew how muany you'd ned at comille time. If you have veridiac runtime argumentents with tempaltes then Fruny is THE MAN...or you could just use the standard sytanx.?


I have no idea what you just said, but I agree, Fruny is a good source.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
This horrible, horrible, horrible, horrible, horrible piece of engineering is brought to you by Mad Cow Disease, and the letter 3.

WARNING: There's an error somewhere in this code. As I type this, my IDE is continuing to spew out the error messages. I have 2^10 different instantiations, and this error is causing a similar number of "instantiated from ..." messages. Needless to say, it's taking awhile.

EDIT: Fixed, I think (compiles and runs without segfault). Made material_base publicly inherited. Go figure that'd cause some 2^10 errors. This is still horrible and evil, and takes a bit to compile - create_material should be implemented within it's own source file, and prototyped in a header. The EXE size isn't too horrible... given that we're working with MinGW which must statically link it's libraries.

C:\eclipse\workspace\evil>g++ --version
g++ (GCC) 3.4.2 (mingw-special)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C:\eclipse\workspace\evil>dir Debug\evil.exe
08/31/2005 05:04 PM 9,079,371 evil.exe

C:\eclipse\workspace\evil>dir Release\evil.exe
08/31/2005 05:05 PM 101,277 evil.exe

C:\eclipse\workspace\evil>dir stripped_evil.exe
08/31/2005 05:09 PM 48,128 evil.exe

#include <boost/array.hpp>

class material_base {};

template <bool AlphaFunc, bool BlendFunc, bool TextureBind, bool CullFace, bool DepthFunc, bool DepthMask, bool ColorMask, bool StencilFunc, bool StencilMask, bool StencilOp>
class material : public material_base { /* etc */ };

template < bool AlphaFunc >
struct create_material_helper_a {
template < bool BlendFunc >
struct create_material_helper_ab {
template < bool TextureBind >
struct create_material_helper_abt {
template < bool CullFace >
struct create_material_helper_abtc {
template < bool DepthFunc >
struct create_material_helper_abtcd {
template < bool DepthMask >
struct create_material_helper_abtcdd {
template < bool ColorMask >
struct create_material_helper_abtcddc {
template < bool StencilFunc >
struct create_material_helper_abtcddcs {
template < bool StencilMask >
struct create_material_helper_abtcddcss {
template < bool StencilOp >
struct create_material_helper_abtcddcsss {
static material_base * create( /*boost::array< bool , 0 > options*/ ) {
return new material< AlphaFunc , BlendFunc , TextureBind , CullFace , DepthFunc , DepthMask , ColorMask , StencilFunc , StencilMask , StencilOp >();
}
};
static material_base * create( boost::array< bool , 1 > options ) {
/*
boost::array< bool , 1 > remaining_options;
for ( size_t i = 0 ; i < 1 ; ++i ) {
remaining_options[i] = options[i + 1];
}
*/

return options[0]
? create_material_helper_abtcddcsss<true>::create( /*remaining_options*/ )
: create_material_helper_abtcddcsss<false>::create( /*remaining_options*/ )
;
}
};
static material_base * create( boost::array< bool , 2 > options ) {
boost::array< bool , 1 > remaining_options;
for ( size_t i = 0 ; i < 1 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abtcddcss<true>::create( remaining_options )
: create_material_helper_abtcddcss<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 3 > options ) {
boost::array< bool , 2 > remaining_options;
for ( size_t i = 0 ; i < 2 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abtcddcs<true>::create( remaining_options )
: create_material_helper_abtcddcs<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 4 > options ) {
boost::array< bool , 3 > remaining_options;
for ( size_t i = 0 ; i < 3 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abtcddc<true>::create( remaining_options )
: create_material_helper_abtcddc<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 5 > options ) {
boost::array< bool , 4 > remaining_options;
for ( size_t i = 0 ; i < 4 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abtcdd<true>::create( remaining_options )
: create_material_helper_abtcdd<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 6 > options ) {
boost::array< bool , 5 > remaining_options;
for ( size_t i = 0 ; i < 5 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abtcd<true>::create( remaining_options )
: create_material_helper_abtcd<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 7 > options ) {
boost::array< bool , 6 > remaining_options;
for ( size_t i = 0 ; i < 6 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abtc<true>::create( remaining_options )
: create_material_helper_abtc<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 8 > options ) {
boost::array< bool , 7 > remaining_options;
for ( size_t i = 0 ; i < 7 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_abt<true>::create( remaining_options )
: create_material_helper_abt<false>::create( remaining_options )
;
}
};
static material_base * create( boost::array< bool , 9 > options ) {
boost::array< bool , 8 > remaining_options;
for ( size_t i = 0 ; i < 8 ; ++i ) {
remaining_options[i] = options[i + 1];
}
return options[0]
? create_material_helper_ab<true>::create( remaining_options )
: create_material_helper_ab<false>::create( remaining_options )
;
}
};

material_base * create_material( bool AlphaFunc, bool BlendFunc, bool TextureBind, bool CullFace, bool DepthFunc, bool DepthMask, bool ColorMask, bool StencilFunc, bool StencilMask, bool StencilOp ) {
boost::array< bool , 9 > remaining_options;
remaining_options[0] = BlendFunc;
remaining_options[1] = TextureBind;
remaining_options[2] = CullFace;
remaining_options[3] = DepthFunc;
remaining_options[4] = DepthMask;
remaining_options[5] = ColorMask;
remaining_options[6] = StencilFunc;
remaining_options[7] = StencilMask;
remaining_options[8] = StencilOp;
return AlphaFunc ? create_material_helper_a< true >::create( remaining_options ) : create_material_helper_a< false >::create( remaining_options );
}

int main () {
delete create_material( true , false , true , false , true , false , true , false , true , false );
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this