S
stephen.diverdi
I have a question about what's the best way to handle something in C++
without a lot of redundant code and void*s because I don't seem to be
able to avoid them both. I've run into it before and always sort of
hacked something together, but I'd really prefer a more elegant
solution.
I have a parameter struct that I store some values of varying type in:
struct params_t
{
int count;
bool render;
float alpha;
};
params_t params;
This struct gets used many different places. For example, it can be
filled with values from a dialog box like:
params->count = Dialog->GetIntegerValue( kParamsCountItem );
params->render = Dialog->GetBooleanValue( kParamsRenderItem );
where kParamsCountItem and kParamsRenderItem are static constants.
Creating the dialog box uses similar functions to set default values:
Dialog->SetIntegerValue( kParamsCountItem, 1 );
Dialog->SetBooleanValue( kParamsRenderItem, false );
There's other code the struct has to interact with that operates more
like this:
dictionary->GetIntegerValue( "count", ¶ms->count );
dictionary->GetFloatValue( "alpha", ¶ms->alpha );
Currently, every time I add a new paramter, or I change a default
value or something, I have to edit a bunch of different things - I
need to update the places where default values are set, I need to add
functions to the dialog handling code, I need to add lines to the
dictionary handling code, etc. This is spread over a couple files and
is tedious and error-prone. I'd like to have something where I define
the set of available parameters in one place statically, and then each
of these separate functions (i.e. dialog, dictionary, etc.) just
iterates over a the set of available parameters. The trouble is my
parameters are different types. Here's the kind of thing I'm looking
at now (which I recognize is a mess):
enum { TYPE_NONE = 0, TYPE_INT, TYPE_BOOL, TYPE_FLOAT };
struct param_spec_t
{
int type;
size_t offset;
const char *str;
float defaultval;
int dialog_id;
};
static const param_spec_t param_spec[] = {
{ TYPE_INT, offsetof( params_t, count ), "count", 1.0f,
kParamsCountItem },
{ TYPE_BOOL, offsetof( params_t, render ), "render", 0.0f,
kParamsRenderItem },
{ TYPE_FLOAT, offsetof( params_t, alpha ), "alpha", 0.5f,
kParamsAlphaItem },
{ 0, 0, NULL, 0, 0 } };
This makes the code to interact with e.g. the dialog box unpleasant:
params_t *params;
for( int i = 0 ; param_spec[ i ].type ; ++i )
{
void *ptr = ( ( void * )params ) + param_spec[ i ].offset;
switch( param_spec[ i ].type )
{
case TYPE_INT:
*( int * )ptr = Dialog-
case TYPE_BOOL:
*( bool * )ptr = Dialog-
case TYPE_FLOAT:
*( float * )ptr = Dialog-
}
}
Anytime I want to iterate through the parameters, this kind of mess is
necessary. So, what's a better way to accomplish this? I'd rather
not throw out type data and have to use these switch statements on an
enum, but how can I store a set of parameters of different types? And
how can I avoid the offsetof mess? Any suggestions are very welcome!
Thanks,
-stephen diverdi
(e-mail address removed)
without a lot of redundant code and void*s because I don't seem to be
able to avoid them both. I've run into it before and always sort of
hacked something together, but I'd really prefer a more elegant
solution.
I have a parameter struct that I store some values of varying type in:
struct params_t
{
int count;
bool render;
float alpha;
};
params_t params;
This struct gets used many different places. For example, it can be
filled with values from a dialog box like:
params->count = Dialog->GetIntegerValue( kParamsCountItem );
params->render = Dialog->GetBooleanValue( kParamsRenderItem );
where kParamsCountItem and kParamsRenderItem are static constants.
Creating the dialog box uses similar functions to set default values:
Dialog->SetIntegerValue( kParamsCountItem, 1 );
Dialog->SetBooleanValue( kParamsRenderItem, false );
There's other code the struct has to interact with that operates more
like this:
dictionary->GetIntegerValue( "count", ¶ms->count );
dictionary->GetFloatValue( "alpha", ¶ms->alpha );
Currently, every time I add a new paramter, or I change a default
value or something, I have to edit a bunch of different things - I
need to update the places where default values are set, I need to add
functions to the dialog handling code, I need to add lines to the
dictionary handling code, etc. This is spread over a couple files and
is tedious and error-prone. I'd like to have something where I define
the set of available parameters in one place statically, and then each
of these separate functions (i.e. dialog, dictionary, etc.) just
iterates over a the set of available parameters. The trouble is my
parameters are different types. Here's the kind of thing I'm looking
at now (which I recognize is a mess):
enum { TYPE_NONE = 0, TYPE_INT, TYPE_BOOL, TYPE_FLOAT };
struct param_spec_t
{
int type;
size_t offset;
const char *str;
float defaultval;
int dialog_id;
};
static const param_spec_t param_spec[] = {
{ TYPE_INT, offsetof( params_t, count ), "count", 1.0f,
kParamsCountItem },
{ TYPE_BOOL, offsetof( params_t, render ), "render", 0.0f,
kParamsRenderItem },
{ TYPE_FLOAT, offsetof( params_t, alpha ), "alpha", 0.5f,
kParamsAlphaItem },
{ 0, 0, NULL, 0, 0 } };
This makes the code to interact with e.g. the dialog box unpleasant:
params_t *params;
for( int i = 0 ; param_spec[ i ].type ; ++i )
{
void *ptr = ( ( void * )params ) + param_spec[ i ].offset;
switch( param_spec[ i ].type )
{
case TYPE_INT:
*( int * )ptr = Dialog-
break;GetIntegerValue( param_spec[ i ].dialog_id );
case TYPE_BOOL:
*( bool * )ptr = Dialog-
break;GetBooleanValue( param_spec[ i ].dialog_id );
case TYPE_FLOAT:
*( float * )ptr = Dialog-
break;GetFloatValue( param_spec[ i ].dialog_id );
}
}
Anytime I want to iterate through the parameters, this kind of mess is
necessary. So, what's a better way to accomplish this? I'd rather
not throw out type data and have to use these switch statements on an
enum, but how can I store a set of parameters of different types? And
how can I avoid the offsetof mess? Any suggestions are very welcome!
Thanks,
-stephen diverdi
(e-mail address removed)