Replacement for "switch" that can use non-const values?



 DEVELOP > c-Plus-Plus > Replacement for "switch" that can use non-const values?

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: ""
Date: 12 Aug 2007 10:45:57 PM
Object: Replacement for "switch" that can use non-const values?
All,
What is a good way to replace a simple switch() statement that relies
on #define'ed magic numbers, with a mechanism that can work with
variable values?
Consider the following code:
#include <iostream>
#define FUNC_1 1000
unsigned GetInt()
{
return 3000;
}
const unsigned FUNC_2 = GetInt();
class Test
{
public:
void Func1()
{
std::cout << "Test::Func1()\n";
}
void Func2()
{
std::cout << "Test::Func2()\n";
}
void Dispatch( unsigned func )
{
switch ( func )
{
case FUNC_1:
Func1();
break;
case FUNC_2: // <-- ERROR!
/*
* switch.cpp:33: error: `FUNC_2' cannot
* appear in a constant-expression
*/
Func2();
break;
}
}
};
int main()
{
Test t;
t.Dispatch( FUNC_1 );
t.Dispatch( FUNC_2 );
}
I've tried a multitude of designs I could come up with to solve this
problem, but non seem elegant or portable when it comes to derived
classes etc. For example, I've tried a std::map with pointers to
member functions, which I liked, but I had trouble making that worked
for derived classes since I needed some template "magic" to get the
function pointers for any given class to work.
Lots of if/else would of course work, but that looks ugly as sin and
can get very, very repetitive, especially when there's a lot of
functions to dispatch.
So what would be a good design that can be applied cleanly to classes
of various level of inheritance?
Thanks,
Andre
.

User: "Ian Collins"

Title: Re: Replacement for "switch" that can use non-const values? 12 Aug 2007 10:56:17 PM
wrote:

All,

What is a good way to replace a simple switch() statement that relies
on #define'ed magic numbers, with a mechanism that can work with
variable values?

Why should a switch depend on #define'ed magic numbers? Switch cases
use compile time constants.
A common technique for "dynamic dispatch" is to use a map of functors or
function pointers, indexed by what ever makes sense as the key for that
particular application.
A very simple example:
typedef void (*Fn)();
std::map<int, Fn> table;
void dispatcher( int n )
{
table[n]();
}
--
Ian Collins.
.
User: ""

Title: Re: Replacement for "switch" that can use non-const values? 12 Aug 2007 11:06:19 PM
On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

All,


What is a good way to replace a simple switch() statement that relies
on #define'ed magic numbers, with a mechanism that can work with
variable values?


Why should a switch depend on #define'ed magic numbers? Switch cases
use compile time constants.

It doesn't. It's just what I am trying to replace.

A common technique for "dynamic dispatch" is to use a map of functors or
function pointers, indexed by what ever makes sense as the key for that
particular application.

A very simple example:

typedef void (*Fn)();

std::map<int, Fn> table;

void dispatcher( int n )
{
table[n]();

}

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.
All hints would be appreciated.
Thanks,
Andre
.
User: "Jim Langston"

Title: Re: Replacement for "switch" that can use non-const values? 12 Aug 2007 11:15:25 PM
<int2str@gmail.com> wrote in message
news:1186977979.615734.254550@i38g2000prf.googlegroups.com...

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

All,


What is a good way to replace a simple switch() statement that relies
on #define'ed magic numbers, with a mechanism that can work with
variable values?


Why should a switch depend on #define'ed magic numbers? Switch cases
use compile time constants.


It doesn't. It's just what I am trying to replace.

A common technique for "dynamic dispatch" is to use a map of functors or
function pointers, indexed by what ever makes sense as the key for that
particular application.

A very simple example:

typedef void (*Fn)();

std::map<int, Fn> table;

void dispatcher( int n )
{
table[n]();

}


Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.

All hints would be appreciated.

A switch simply replaces an if...else block.
void Dispatch( unsigned func )
{
if ( func == FUNC_1 )
{
Func1();
break;
}
else if ( func == FUNC_2 )
{
Func2();
break;
}
}
.
User: ""

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 12:10:52 AM
On Aug 12, 9:15 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.


All hints would be appreciated.


A switch simply replaces an if...else block.

Yes, but IMHO that's very ugly and repetitive.
.
User: "James Kanze"

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 03:58:00 AM
On Aug 13, 7:10 am, "int2...@gmail.com" <int2...@gmail.com> wrote:

On Aug 12, 9:15 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.
All hints would be appreciated.

A switch simply replaces an if...else block.

Yes, but IMHO that's very ugly and repetitive.

It's actually better structured than the switch you started
with. It's definitly the classical solution.
If not, you can always use a map:
class DoIt
{
public:
virtual ~DoIt() {}
virtual void operator()() const =3D 0 ;
} ;
std::map< int, DoIt const* > myMap ;
But you have to define a separate derived class for each case,
and initialize the map somehow. It may be appropriate, but it
does a lot more than a switch, and if a switch was fully
appropriate, then the chained if/else if would probably be more
appropriate. (On the other hand, if the switch was being used
simply because in C, you didn't have any other mechanism, and
each case of the switch is just a single function call, then the
idiom using a map might be more appropriate. Done correctly,
there is no central point where all of the cases are enumerated.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.

User: "Jorgen Grahn"

Title: Re: Replacement for "switch" that can use non-const values? 14 Aug 2007 11:37:13 AM
On Mon, 13 Aug 2007 05:10:52 -0000,
<
> wrote:

On Aug 12, 9:15 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.


All hints would be appreciated.


A switch simply replaces an if...else block.


Yes, but IMHO that's very ugly and repetitive.

- You lose the word "case" and gain "else if"
- You lose the word "break" and gain a few curly brackets
- You repeat the name of the variable (you may want to create
a const variable with a short name, if the expression in switch(...)
was long and unwieldy or expensive).
No big deal if you format it sensibly, IMHO.
/Jorgen
--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.dyndns.org> R'lyeh wgah'nagl fhtagn!
.
User: "Ian Collins"

Title: Re: Replacement for "switch" that can use non-const values? 14 Aug 2007 04:21:16 PM
Jorgen Grahn wrote:

On Mon, 13 Aug 2007 05:10:52 -0000,

<
> wrote:

On Aug 12, 9:15 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.
All hints would be appreciated.

A switch simply replaces an if...else block.

Yes, but IMHO that's very ugly and repetitive.


- You lose the word "case" and gain "else if"
- You lose the word "break" and gain a few curly brackets
- You repeat the name of the variable (you may want to create
a const variable with a short name, if the expression in switch(...)
was long and unwieldy or expensive).

No big deal if you format it sensibly, IMHO.

You forgot
- You loose the simple optimisation of a jump table with appropriate
case labels.
--
Ian Collins.
.
User: "Jorgen Grahn"

Title: Re: Replacement for "switch" that can use non-const values? 24 Aug 2007 06:20:12 AM
On Wed, 15 Aug 2007 09:21:16 +1200, Ian Collins <ian-news@hotmail.com> wrote:

Jorgen Grahn wrote:

On Mon, 13 Aug 2007 05:10:52 -0000,

<
> wrote:

On Aug 12, 9:15 pm, "Jim Langston" <tazmas...@rocketmail.com> wrote:

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.
All hints would be appreciated.

A switch simply replaces an if...else block.

Yes, but IMHO that's very ugly and repetitive.


- You lose the word "case" and gain "else if"
- You lose the word "break" and gain a few curly brackets
- You repeat the name of the variable (you may want to create
a const variable with a short name, if the expression in switch(...)
was long and unwieldy or expensive).

No big deal if you format it sensibly, IMHO.

You forgot

- You loose the simple optimisation of a jump table with appropriate
case labels.

Yes, of course. But it was my impression that he was prepared to give
that up, mostly complaining about the ugliness and repetitiveness.
/Jorgen
--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.dyndns.org> R'lyeh wgah'nagl fhtagn!
.





User: "Ian Collins"

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 12:44:44 AM
wrote:

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

All,
What is a good way to replace a simple switch() statement that relies
on #define'ed magic numbers, with a mechanism that can work with
variable values?

Why should a switch depend on #define'ed magic numbers? Switch cases
use compile time constants.


It doesn't. It's just what I am trying to replace.

A common technique for "dynamic dispatch" is to use a map of functors or
function pointers, indexed by what ever makes sense as the key for that
particular application.

A very simple example:

typedef void (*Fn)();

std::map<int, Fn> table;

void dispatcher( int n )
{
table[n]();

}


Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.

All hints would be appreciated.

Pointers to members of the same class, or different classes?
--
Ian Collins.
.
User: ""

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 12:48:27 AM
On Aug 12, 10:44 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

All,
What is a good way to replace a simple switch() statement that relies
on #define'ed magic numbers, with a mechanism that can work with
variable values?

Why should a switch depend on #define'ed magic numbers? Switch cases
use compile time constants.


It doesn't. It's just what I am trying to replace.


A common technique for "dynamic dispatch" is to use a map of functors or
function pointers, indexed by what ever makes sense as the key for that
particular application.


A very simple example:


typedef void (*Fn)();


std::map<int, Fn> table;


void dispatcher( int n )
{
table[n]();


}


Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.


All hints would be appreciated.


Pointers to members of the same class, or different classes?

Same class.
.
User: "Ian Collins"

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 02:17:40 AM
wrote:

On Aug 12, 10:44 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:
Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.
All hints would be appreciated.

Pointers to members of the same class, or different classes?


Same class.

The just change the typedef to be a pointer to member type.
#include <map>
struct X {
void fn() {}
};
X x;
typedef void (X::*Fn)();
std::map<int, Fn> table;
void loader( int n, Fn fn) {
table[n] = fn;
}
void dispatcher( int n ) {
(x.*table[n])();
}
int main() {
loader( 1, &X::fn );
dispatcher( 1 );
}
--
Ian Collins.
.
User: ""

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 09:32:01 AM
[long post warning - lots of (bad?) code ahead...]
On Aug 13, 12:17 am, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

On Aug 12, 10:44 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:
Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.
All hints would be appreciated.

Pointers to members of the same class, or different classes?


Same class.


The just change the typedef to be a pointer to member type.

#include <map>

struct X {
void fn() {}

};

X x;

typedef void (X::*Fn)();

std::map<int, Fn> table;

void loader( int n, Fn fn) {
table[n] = fn;

}

void dispatcher( int n ) {
(x.*table[n])();

}

int main() {
loader( 1, &X::fn );
dispatcher( 1 );

}

Ok, so I lied...
I actually do have different classes. Since I'm trying to make this
generic so I can apply the mechanism to various classes. Furthermore,
I'd like something where I can apply the mechanism to a base class,
but also use it in a derived class.
So here's what I came up with:
---------- FILE: dynamicdispatch.h ----------
Link to formatted source code here:
http://ironcreek.net/code/dynamicdispatch.h
#ifndef DYNAMICDISPATCH_H
#define DYNAMICDISPATCH_H
#include <map>
#define REGISTERMSG(msg, class, func) RegisterHandler( msg, new
MsgHandler<class>( this, &class::func ));
class IMsgHandler
{
public:
virtual unsigned Handle( unsigned, unsigned ) = 0;
};
template <typename T>
class MsgHandler : public IMsgHandler
{
public:
typedef unsigned (T::*HandlerFunc)( unsigned, unsigned );
MsgHandler( T* pobj, HandlerFunc handler )
: obj( pobj )
, func( handler )
{
}
unsigned Handle( unsigned p1, unsigned p2 )
{
return (obj->*func)( p1, p2 );
}
protected:
T *obj;
HandlerFunc func;
};
class DynamicDispatch
{
public:
~DynamicDispatch()
{
std::map<unsigned, IMsgHandler*>::iterator ii;
for( ii = func_map.begin(); ii != func_map.end(); ++ii )
delete ii->second;
}
void RegisterHandler( unsigned msg, IMsgHandler *p_handler )
{
func_map[ msg ] = p_handler;
}
unsigned HandleMessage( unsigned msg, unsigned p1, unsigned p2 )
{
std::map<unsigned, IMsgHandler*>::iterator ii =
func_map.find( msg );
if ( ii != func_map.end() )
return ii->second->Handle( p1, p2 );
return 0;
}
protected:
std::map<unsigned, IMsgHandler*> func_map;
};
#endif
---------- FILE: funcmap.cpp ----------
Link to formatted source code here:
http://ironcreek.net/code/funcmap.cpp
#include <iostream>
#include "dynamicdispatch.h"
const unsigned FIRST_EVENT = 1000;
const unsigned SECOND_EVENT = 2000;
const unsigned THIRD_EVENT = 3000;
class Dialog : public DynamicDispatch
{
public:
Dialog()
{
REGISTERMSG( THIRD_EVENT, Dialog, MyEvent );
}
unsigned MyEvent( unsigned, unsigned )
{
std::cout << "Dialog::MyEvent()\n";
return 0;
}
};
class MyDlg : public Dialog
{
public:
MyDlg()
{
REGISTERMSG( FIRST_EVENT, MyDlg, Func1 );
REGISTERMSG( SECOND_EVENT, MyDlg, Func2 );
}
unsigned Func1( unsigned p1, unsigned p2 )
{
std::cout << "MyDlg::Func1() p1=" << p1 << " p2=" << p2 <<
"\n";
return 0;
}
unsigned Func2( unsigned p1, unsigned p2 )
{
std::cout << "MyDlg::Func2() p1=" << p1 << " p2=" << p2 <<
"\n";
return 0;
}
void Test()
{
HandleMessage( FIRST_EVENT, 11, 22 );
HandleMessage( SECOND_EVENT, 11, 22 );
HandleMessage( THIRD_EVENT, 11, 22 );
}
};
int main()
{
MyDlg dlg;
dlg.Test();
}
Now, I am _reasonably_ happy with that code - except for one thing.
The macro (REGISTERMSG) I use to register the message handlers. But
the alternative syntax that the macro masks, is a bit hard on the eye
if repeated often...
So what do you guys think about this code and are there any
suggestions to make the REGISTERMSG() functionality not a macro, but
still as clean as possible?
Thanks,
Andre
.
User: "Jim Langston"

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 10:50:03 AM
<int2str@gmail.com> wrote in message
news:1187015521.684758.80270@g12g2000prg.googlegroups.com...

[long post warning - lots of (bad?) code ahead...]

On Aug 13, 12:17 am, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

On Aug 12, 10:44 pm, Ian Collins <ian-n...@hotmail.com> wrote:

int2...@gmail.com wrote:

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:
Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I
can't
come up with a clean setup.
All hints would be appreciated.

Pointers to members of the same class, or different classes?


Same class.


The just change the typedef to be a pointer to member type.

#include <map>

struct X {
void fn() {}

};

X x;

typedef void (X::*Fn)();

std::map<int, Fn> table;

void loader( int n, Fn fn) {
table[n] = fn;

}

void dispatcher( int n ) {
(x.*table[n])();

}

int main() {
loader( 1, &X::fn );
dispatcher( 1 );

}


Ok, so I lied...
I actually do have different classes. Since I'm trying to make this
generic so I can apply the mechanism to various classes. Furthermore,
I'd like something where I can apply the mechanism to a base class,
but also use it in a derived class.

So here's what I came up with:

---------- FILE: dynamicdispatch.h ----------

Link to formatted source code here:
http://ironcreek.net/code/dynamicdispatch.h

#ifndef DYNAMICDISPATCH_H
#define DYNAMICDISPATCH_H

#include <map>

#define REGISTERMSG(msg, class, func) RegisterHandler( msg, new
MsgHandler<class>( this, &class::func ));

class IMsgHandler
{
public:
virtual unsigned Handle( unsigned, unsigned ) = 0;
};

template <typename T>
class MsgHandler : public IMsgHandler
{
public:
typedef unsigned (T::*HandlerFunc)( unsigned, unsigned );

MsgHandler( T* pobj, HandlerFunc handler )
: obj( pobj )
, func( handler )
{
}

unsigned Handle( unsigned p1, unsigned p2 )
{
return (obj->*func)( p1, p2 );
}

protected:
T *obj;
HandlerFunc func;
};

class DynamicDispatch
{
public:
~DynamicDispatch()
{
std::map<unsigned, IMsgHandler*>::iterator ii;
for( ii = func_map.begin(); ii != func_map.end(); ++ii )
delete ii->second;
}

void RegisterHandler( unsigned msg, IMsgHandler *p_handler )
{
func_map[ msg ] = p_handler;
}

unsigned HandleMessage( unsigned msg, unsigned p1, unsigned p2 )
{
std::map<unsigned, IMsgHandler*>::iterator ii =
func_map.find( msg );
if ( ii != func_map.end() )
return ii->second->Handle( p1, p2 );
return 0;
}

protected:
std::map<unsigned, IMsgHandler*> func_map;
};

#endif


---------- FILE: funcmap.cpp ----------

Link to formatted source code here:
http://ironcreek.net/code/funcmap.cpp

#include <iostream>
#include "dynamicdispatch.h"

const unsigned FIRST_EVENT = 1000;
const unsigned SECOND_EVENT = 2000;
const unsigned THIRD_EVENT = 3000;

class Dialog : public DynamicDispatch
{
public:
Dialog()
{
REGISTERMSG( THIRD_EVENT, Dialog, MyEvent );
}

unsigned MyEvent( unsigned, unsigned )
{
std::cout << "Dialog::MyEvent()\n";
return 0;
}
};

class MyDlg : public Dialog
{
public:
MyDlg()
{
REGISTERMSG( FIRST_EVENT, MyDlg, Func1 );
REGISTERMSG( SECOND_EVENT, MyDlg, Func2 );
}

unsigned Func1( unsigned p1, unsigned p2 )
{
std::cout << "MyDlg::Func1() p1=" << p1 << " p2=" << p2 <<
"\n";
return 0;
}

unsigned Func2( unsigned p1, unsigned p2 )
{
std::cout << "MyDlg::Func2() p1=" << p1 << " p2=" << p2 <<
"\n";
return 0;
}

void Test()
{
HandleMessage( FIRST_EVENT, 11, 22 );
HandleMessage( SECOND_EVENT, 11, 22 );
HandleMessage( THIRD_EVENT, 11, 22 );
}
};

int main()
{
MyDlg dlg;
dlg.Test();
}


Now, I am _reasonably_ happy with that code - except for one thing.
The macro (REGISTERMSG) I use to register the message handlers. But
the alternative syntax that the macro masks, is a bit hard on the eye
if repeated often...

So what do you guys think about this code and are there any
suggestions to make the REGISTERMSG() functionality not a macro, but
still as clean as possible?

I can't understand why you would want to switch from using if...else to this
kludge. You thought if...else was ugly and repetitive but this isn't?
.
User: "Gianni Mariani"

Title: Re: Replacement for "switch" that can use non-const values? 14 Aug 2007 05:57:23 PM
Jim Langston wrote:
....


I can't understand why you would want to switch from using if...else to this
kludge. You thought if...else was ugly and repetitive but this isn't?

Using the methodology described here, you can extend the system without
needing to change the dispatch code. Centralized dispatchers (if/else
or switch) can become very large and confusing very quickly with a
moderate number of cases.
Dynamic dispatchers also conform to the "code is in one place" rule. It
means if you need a new case in your switch statement, you don't have to
change the code other than the one place where you define all the
aspects of that new case. I had worked on one system that when a new
message type was added, 11 different files needed to be "fixed".
Needless to say it was a very tedious and error prone thing to do.
Using the dynamic dispatch mechanism, you would only need to add a new
file containing all the mechanisms you need.
Think of systems like driver modules in a kernel or protocol handlers etc.
You can take this to extremes where the dynamic selection of the case is
actually a complex process and it allows you to eliminate considerable
chunks of if/else garbage. This I used in a system where the processing
was dependent on a large number of dynamic factors.
C++ also allows you to use the technique statically with templates using
partial specializations. i.e. you can change the behaviour of the code
simply by adding a specialization of a class. I've used that in a DXF
file reader which was one of those "worked first time" miracles. The
nice thing with the DXF file reader architecture, I don't even need to
add new code body, all I have to do is add a new specialized class. The
code also reflects closely to the documentation which means that it is
easy to verify that the code is doing what the documentation expects.
The corresponding if/else or switch code would have been a nightmare to
maintain and validate.
.
User: "Jim Langston"

Title: Re: Replacement for "switch" that can use non-const values? 15 Aug 2007 03:30:42 AM
"Gianni Mariani" <gi3nospam@mariani.ws> wrote in message
news:46c23354$0$22601$5a62ac22@per-qv1-newsreader-01.iinet.net.au...

Jim Langston wrote:
...


I can't understand why you would want to switch from using if...else to
this kludge. You thought if...else was ugly and repetitive but this
isn't?


Using the methodology described here, you can extend the system without
needing to change the dispatch code. Centralized dispatchers (if/else or
switch) can become very large and confusing very quickly with a moderate
number of cases.

Dynamic dispatchers also conform to the "code is in one place" rule. It
means if you need a new case in your switch statement, you don't have to
change the code other than the one place where you define all the aspects
of that new case. I had worked on one system that when a new message
type was added, 11 different files needed to be "fixed". Needless to say
it was a very tedious and error prone thing to do. Using the dynamic
dispatch mechanism, you would only need to add a new file containing all
the mechanisms you need.

Think of systems like driver modules in a kernel or protocol handlers etc.

You can take this to extremes where the dynamic selection of the case is
actually a complex process and it allows you to eliminate considerable
chunks of if/else garbage. This I used in a system where the processing
was dependent on a large number of dynamic factors.

C++ also allows you to use the technique statically with templates using
partial specializations. i.e. you can change the behaviour of the code
simply by adding a specialization of a class. I've used that in a DXF
file reader which was one of those "worked first time" miracles. The nice
thing with the DXF file reader architecture, I don't even need to add new
code body, all I have to do is add a new specialized class. The code also
reflects closely to the documentation which means that it is easy to
verify that the code is doing what the documentation expects. The
corresponding if/else or switch code would have been a nightmare to
maintain and validate.

I whole heartedly agree that dispatch systems have their place. I have used
them before myself in fact. But I would by no means use one just to replace
a branch of if...else if with a dispatch system. It is, IMO, harder to
follow the flow of code using dispatch system than a switch statement or
if...else block, especially depending on the method the dispatch system
uses.
.
User: "Ian Collins"

Title: Re: Replacement for "switch" that can use non-const values? 15 Aug 2007 03:36:14 AM
Jim Langston wrote:


I whole heartedly agree that dispatch systems have their place. I have used
them before myself in fact. But I would by no means use one just to replace
a branch of if...else if with a dispatch system. It is, IMO, harder to
follow the flow of code using dispatch system than a switch statement or
if...else block, especially depending on the method the dispatch system
uses.

With Dynamic dispatch you can add cases to an existing dispatcher at
both compile and run time without updating its code, something a switch
or if/else block can never do.
Software design isn't a one shoe fits all practice, use the most
appropriate solution for the problem at hand.
--
Ian Collins.
.






User: "hurcan solter"

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 01:30:12 AM
from the top of my head;
#include <iostream>
#include <map>
class A{
public:
void foo1(){std::cout<<"foo1\n";}
void foo2(){std::cout<<"foo2\n";}
};
typedef void(A::*fp)();
std::map<int,fp> fpmap;
void dispatch(A& a,int index)
{
(a.*fpmap[index])();
}
int main()
{
fpmap[1]=&A::foo1;
fpmap[2]=&A::foo2;
A a;
dispatch(a,1);
dispatch(a,2);
}
not very much different from ordinary function pointer really.
.



User: "Frank Birbacher"

Title: Re: Replacement for "switch" that can use non-const values? 13 Aug 2007 06:05:04 AM
Hi!
int2str@gmail.com schrieb:

On Aug 12, 8:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:

Why should a switch depend on #define'ed magic numbers? Switch cases
use compile time constants.


It doesn't. It's just what I am trying to replace.

Switch works with compile time constants. But FUNC_2 is not a compile
time constant in your example. Its value is not computed at compile time
but at run time.

Yes, that's exactly what I'd like to do. Except that I need pointers
to member functions, which gets complicated (at least for me). I can't
come up with a clean setup.

I tried some dynamic casting recently:
Work with boost::function<void (BaseClass*)> and put a function into it,
that dynamic_casts its argument to the derived class and then calls the
member function on it. Then you can have these boost::function instances
in a map or array/vector (when the key is an int).
Frank
.




  Page 1 of 1

1

 


Related Articles
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER