Comparison of Callback and Template

A. First Edition
This is only a simple demo of comparison of "callback" and template implementation.
B.The problem

Suppose you need write a general method for other users, allowing the user to use its self-defined method in

your method, how to implement it?

The typical answer is "callback" function. Besides it, you can use a template class. Here I just want to demo

how to do it.

这个小例子是我们都玩过的剪刀石头布。有一个裁判程序(judge),你和我都有一个出手的程序(youFight, meFight)和以及各自的策略数据(yourStrategy,
myStrategy)。使用的时候就把他们都当作参数带入裁判程序。
为什么要这样写呢?原因就是flexibility,假如,你忽然想要改变策略数据的话,就换一个参数带入就好了,裁判时不用变得。你也可以改变你的出牌的方法
也就是重新定义一个新函数,只要参数类型个数,返回值类型与现在的一样就可以了,比如说,改变shift的值,或者就干脆用随机数等等。

 

C.The idea of program
 
The program is like a little game which we all played in childhood: "scissors-stone-cloth". The game is cycle-
 
win: scissors>cloth>stone>scissors.
 
Now you are asked to write a "judge" program which take two player's parameters. The parameter includes their
 
strategy of how to play the game, or more probably along with their data of strategy, say an array of playing
 
strategy. Your "judge" program call the parameters and get the choices from each of two players and judge the
 
the winner, show the winning information. That's it.
 
The first approach is by "callback" function which passes function pointer as parameter, along with their
 
strategy array. It is most common one.
 
The second approach is to pass a user-defined class which has "static" method and data. When the static method
 
is called, they will extract static strategy from its private data member and give the choice. It is more
 
completely wrapped method. However, there is a big bug of VC++6.0 as the compiler doesn't recognize the template
 
function from its declaration. This is a same annoying bug I encountered when overloading friend function of
 
"ostream".
 
D.The major functions
E.Further improvement
 
F.File listing
1. callback.cpp
2. template.cpp
CallBack Method:
file name: callback.cpp
#include <iostream>

using namespace std;

//this is not a program, but a joke...hahha...
const int MatchNumber=10;

//you know what they are, right?
//we all play this little game
enum FightType
{Scissor, Stone, Cloth};

char* typeStr[3]={"Scissor", "Stone", "Cloth"};

//this is the sequence you might play
int yourStrategy[MatchNumber]={2,1,0,2,1,2,0,2,1,1};
//this is the sequence I might play
int myStrategy[MatchNumber]={0,1,2,1,2,1,0,2,1,0};


//this is the match judge, with two your play function and your strategy
//and my function and my strategy
void judge(int (* youPlay)(int* yourParam, int theNumber), int* yourParam, 
			 int (*myPlay)(int* myParam, int theNumber), int* myParam);

//actually this is the function you defined here
int youFight(int* youParam, int index);
//I won't repeat
int meFight(int* myParam, int index);

int main()
{
	judge(youFight, yourStrategy, meFight, myStrategy);
	return 0;
}




void judge(int (* youPlay)(int* theParam, int index), int* yourParam, 
			 int (*myPlay)(int* theParam, int index), int* myParam)
{
	int you, me;
	for (int i=0; i<MatchNumber; i++)
	{
		you=youPlay(yourParam, i);
		me=myPlay(myParam, i);
		cout<<"your type is:"<<typeStr[you]<<endl;
		cout<<"my type is:"<<typeStr[me]<<endl;
		switch (you-me)
		{
			
		case 0:
			
			cout<<"it is a tie on match no."<<i+1<<endl;
			break;
		case 1:
		case -2:
			cout<<"you win on match no. "<<i+1<<endl;
			break;
		case -1:
		case 2:
			cout<<"you lose on match no."<<i+1<<endl;
			break;
		}
	}
}

//you can change your strategy simple by....
int youFight(int* youParam, int index)
{
	//actually you can define any method you imagine
	return yourStrategy[(index+5)%MatchNumber];
}

int meFight(int* myParam, int index)
{
	//by shifting the current strategy, you have a new one
	return myStrategy[(index+2)%MatchNumber];
}
Template Method:
The result of callback method:
your type is:Cloth
my type is:Cloth
it is a tie on match no.1
your type is:Scissor
my type is:Stone
you lose on match no.2
your type is:Cloth
my type is:Cloth
it is a tie on match no.3
your type is:Stone
my type is:Stone
it is a tie on match no.4
your type is:Stone
my type is:Scissor
you win on match no. 5
your type is:Cloth
my type is:Cloth
it is a tie on match no.6
your type is:Stone
my type is:Stone
it is a tie on match no.7
your type is:Scissor
my type is:Scissor
it is a tie on match no.8
your type is:Cloth
my type is:Scissor
you lose on match no.9
your type is:Stone
my type is:Stone
it is a tie on match no.10
Press any key to continue


file name: rules.cpp 
#include <iostream>

using namespace std;

//this is not a program, but a joke...hahha...
const int MatchNumber=10;

//you know what they are, right?
//we all play this little game
enum FightType
{Scissor, Stone, Cloth};

char* typeStr[3]={"Scissor", "Stone", "Cloth"};


class YourPlay
{
private:
	static int yourStrategy[MatchNumber];
public:
	static int youFight(int index)
	{
		//actually you can define any method you imagine
		return yourStrategy[(index+5)%MatchNumber];
	}
};

class MyPlay
{
private:
	static int myStrategy[MatchNumber];
public:
	static int meFight(int index)
	{
		//by shifting the current strategy, you have a new one
		return myStrategy[(index+2)%MatchNumber];
	}
};

//the static strategy is initialized here
int YourPlay::yourStrategy[MatchNumber]={2,1,0,2,1,2,0,2,1,1};
int MyPlay::myStrategy[MatchNumber]={0,1,2,1,2,1,0,2,1,0};

//THIS IS THE BUG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//you cannot declare the template function
//compiler don't recognize it!!!
//believe it or not, try declare it as following:
/*
template<class yourPlayClass , class myPlayClass>
void judge();
*/
//and put the implementation below after "MAIN" function
//then you will get memory access error, because 
//what you declared is not implemented!!!!!
template<class yourPlayClass , class myPlayClass>
void judge()
{
	int you, me;
	for (int i=0; i<MatchNumber; i++)
	{
		you=yourPlayClass::youFight(i);
		me=myPlayClass::meFight(i);
		cout<<"your type is:"<<typeStr[you]<<endl;
		cout<<"my type is:"<<typeStr[me]<<endl;
		switch (you-me)
		{
			
		case 0:
			
			cout<<"it is a tie on match no."<<i+1<<endl;
			break;
		case 1:
		case -2:
			cout<<"you win on match no. "<<i+1<<endl;
			break;
		case -1:
		case 2:
			cout<<"you lose on match no."<<i+1<<endl;
			break;
		}
	}
}



int main()
{
	judge<YourPlay, MyPlay>();
	return 0;
}



The result of callback method:
your type is:Cloth
my type is:Cloth
it is a tie on match no.1
your type is:Scissor
my type is:Stone
you lose on match no.2
your type is:Cloth
my type is:Cloth
it is a tie on match no.3
your type is:Stone
my type is:Stone
it is a tie on match no.4
your type is:Stone
my type is:Scissor
you win on match no. 5
your type is:Cloth
my type is:Cloth
it is a tie on match no.6
your type is:Stone
my type is:Stone
it is a tie on match no.7
your type is:Scissor
my type is:Scissor
it is a tie on match no.8
your type is:Cloth
my type is:Scissor
you lose on match no.9
your type is:Stone
my type is:Stone
it is a tie on match no.10
Press any key to continue




 




                                 back.gif (341 bytes)       up.gif (335 bytes)         next.gif (337 bytes)