Pass a type into a function or something else?

Pages: 12
I have the following (incomplete) code...

Is there a way to have a single function that perhaps passes a type (or something) to do what is the same job to the relevant variables/types for each function in this class?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "ServoLibrary.h"

void servoLibrary::addServoGroupMapping(servoGroupMapping mapping, basicDesc description) {
	servoGroupMapping* mappingItemsTemp = new servoGroupMapping[numberOfMappings];
	basicDesc* mappingNamesTemp = new basicDesc[numberOfMappings];

	for (basicLoop i = 0; i < numberOfMappings; i++) {
		mappingItemsTemp[i] = mappingItems[0];
		mappingNamesTemp[i] = mappingNames[0];
	}

	mappingItems = mappingItemsTemp;
	mappingNames = mappingNamesTemp;
	numberOfMappings++;
};

void servoLibrary::addServoGroupTransition(servoGroupTransition transition, basicDesc description) {
	servoGroupTransition* transitionItemsTemp = new servoGroupTransition[numberOfTransitions];
	basicDesc* transitionNamesTemp = new basicDesc[numberOfTransitions];

	for (basicLoop i = 0; i < numberOfTransitions; i++) {
		transitionItemsTemp[i] = transitionItems[0];
		transitionNamesTemp[i] = transitionNames[0];
	}

	transitionItems = transitionItemsTemp;
	transitionNames = transitionNamesTemp;
	numberOfTransitions++;
};

void servoLibrary::addServoAnimation(servoAnimation animation, basicDesc description) {
	servoAnimation* animationItemsTemp = new servoAnimation[numberOfAnimations];
	basicDesc* animationNamesTemp = new basicDesc[numberOfAnimations];

	for (basicLoop i = 0; i < numberOfAnimations; i++) {
		animationItemsTemp[i] = animationItems[0];
		animationNamesTemp[i] = animationNames[0];
	}

	animationItems = animationItemsTemp;
	animationNames = animationNamesTemp;
	numberOfAnimations++;
};


Thanks
I read that sentence back and it made no sense... reworded:

I have 3 functions. They are all the same expect for the variables they read/write to (and the datatypes they use). Is there a way to not have 3 almost identical bits of code and instead 1 single function that I can call from the 3 functions?

Thanks
Have you ever heard of templates?
No, will google now... nice one :)


Edit: Googled and that sounds like what I am looking for... thanks man!
Last edited on
You could overload the the function. Call it something like addServoObject then make a version that accepts a servoGroupMapping object, a version that acccepts a servoTransition object and a version that takes a servoAnimation object. This would involve writing the function three times, with different parameters for each version.

Personally, I would avoid it, though. When you call these functions in your code currently, it's easy to tell what you're calling. If you have an overloaded function, it becomes a little unclearer (you'd have to rely on the parameter name to get an indication of which one you're calling).

If you do opt to overload, here's a short example which you should be able to apply to your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Print(char a)   // 1
{
   cout << a << endl;
}

void Print(int x)    // 2
{
   cout << x << endl;
}

// Calls...
char my_char = 'a';
int my_int = 5;

Print(my_char);  // Calls 1
Print(my_int);   // Calls 2 
Last edited on
Overloading wouldn't reduce the amount of code... just replicate the name?

Templates:

I wrote this quickly ... can you please advise on any mistakes?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void servoLibrary::addServoGroupMapping(servoGroupMapping mapping, basicDesc description) {
	addItem<servoGroupMapping>(mapping, description, numberOfMappings, mappingItems, mappingNames);
}

template <class T>
addItem(T itemToAdd, basicDesc description, basicCount &count, T* itemslist, basicDesc* nameslist) {
	T* ItemsTemp = new T[count];
	basicDesc* NamesTemp = new basicDesc[count];

	for (basicLoop i = 0; i < count; i++) {
		ItemsTemp[i] = itemslist[i];
		NamesTemp[i] = nameslist[i];
	}

	itemslist = ItemsTemp;
	nameslist = NamesTemp;
	count++;
}


Previous version:

1
2
3
4
5
6
7
8
9
10
11
12
13
void servoLibrary::addServoGroupMapping(servoGroupMapping mapping, basicDesc description) {
	servoGroupMapping* mappingItemsTemp = new servoGroupMapping[numberOfMappings];
	basicDesc* mappingNamesTemp = new basicDesc[numberOfMappings];

	for (basicLoop i = 0; i < numberOfMappings; i++) {
		mappingItemsTemp[i] = mappingItems[i];
		mappingNamesTemp[i] = mappingNames[i];
	}

	mappingItems = mappingItemsTemp;
	mappingNames = mappingNamesTemp;
	numberOfMappings++;
};


Thanks
Last edited on
Had an example but iHutch105 beat me to it. I would agree with him, however, in that those functions may be better off being called as-is. If you still want to call 1 function, with only 3 different types I would definitely go with overloading over a template due to the added difficulty templates usually bring to debugging.
addItem(T itemToAdd, basicDesc description, basicCount &count, T* itemslist, basicDesc* nameslist)

This bit is clearly wrong, ummmm
The point of this exercise is not to have a single (overloaded) function but 3 functions calling a single function so I only have 1 lot of code.
The point of this exercise is not to have a single (overloaded) function but 3 functions calling a single function so I only have 1 lot of code.

I'm a bit lost here. Can you elaborate?
The more I look at that code the less sure I am that a template would work out very well. There's a lot more than just differing argument types.

Edit: Actually those functions aren't even doing anything with the 1st argument (mapping, transition, and animation respectively).

Edit 2: Why do those functions end with semicolons?
Last edited on
iHutch105... instead of:

1
2
3
4
5
6
7
8
9
10
11
void functionA() {
//lots of code
}

void functionB() {
//lots of code
}

void functionC() {
//lots of code
}


I would like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void functionA() {
//single line to call functionGeneric
}

void functionB() {
//single line to call functionGeneric
}

void functionC() {
//single line to call functionGeneric
}

void functionGeneric() {
//lots of code
}



Ikaron:

There are different types and different varibles... it seems to me templates are the answer. Do you not agree?
Ikaron: Please don't get distracted with my poor C++... this code was an example cut down from a bigger piece of code. The semicolons are down to my poor coding... but please don't let them be the issue here... if that's OK.

My question is a valid one even if my programming standards are not :)
But why would you want a function that has a single line call to functionGeneric?

Why not just call functionGeneric?

I think Athar's template suggestion is the way to go if this is the sort of thing you're trying to achieve. In answer to your earlier question, yes, an overloaded function would have to be written three times. It wouldn't reduce your code, just allow you to call a different functions of the same name (with different parameters).
I know I could just call function generic but that would be more complicated at a later date... it would need 5(?) parameters instead of 2.

I will maintain with the templates... thanks
A template is good in a situation where, for a basic example, you want to get the larger value of 2 numbers but you don't know what type those numbers will be, whether they're ints, shorts, floats, doubles, etc. a template allows you to specify the type for the numbers you pass in. However these functions have way more than just differing argument / return types.

As an example of different types between addServoGroupMapping and addServoGroupTransition:

servoGroupMapping // Argument
numberOfMappings
mappingItems // unsure of what this type is supposed to be exactly
mappingNames // unsure of what this type is supposed to be exactly

servoGroupTransition // Argument
numberOfTransitions
transitionItems // unsure of what this type is supposed to be exactly
transitionNames // unsure of what this type is supposed to be exactly

A template will readily replace the differing argument types but what of all the other types?
Last edited on
Ikaron:
mapping/transitionItems is a pointer to array of type I would be passing in.
mapping/transitionNames is a pointer to an array of basicDesc.

Attempt 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template <class T>
void addItem(T itemToAdd, basicDesc description, basicCount &count, T* itemslist, basicDesc* nameslist) {
	T* ItemsTemp = new T[count];
	basicDesc* NamesTemp = new basicDesc[count];

	for (basicLoop i = 0; i < count; i++) {
		ItemsTemp[i] = itemslist[i];
		NamesTemp[i] = nameslist[i];
	}

	itemslist = ItemsTemp;
	nameslist = NamesTemp;
	count++;
}

void servoLibrary::addServoGroupMapping(servoGroupMapping mapping, basicDesc description) {
	addItem<servoGroupMapping>(mapping, description, numberOfMappings, mappingItems, mappingNames);
}

void servoLibrary::addServoGroupTransition(servoGroupTransition transition, basicDesc description) {
	addItem<servoGroupTransition>(transition, description, numberOfTransitions, transitionItems, transitionNames);
}

void servoLibrary::addServoAnimation(servoAnimation animation, basicDesc description) {
	addItem<servoAnimation>(animation, description, numberOfAnimations, animationItems, animationNames);
}


It compiles at least... can't test it yet
Last edited on
Because it more friendly to work with later

Is this better?

1
2
template <class T>
void addItem(T itemToAdd, basicDesc description, basicCount &count, T* &itemslist, basicDesc* &nameslist) {

Instead of passing three additional arguments (count, itemsList, namesList) I would rather create a structure with 3 fields and pass its reference.

Also, I think you use 'count' incorrectly. Is it an input or an output, because currently you use it for both?

@Ikaron
Algorithm is exactly the same in all cases, therefore repeating the code would be, hmm... unoptimal. Even if types of transitionItems and transitionNames were not that easy to determine, you could still use some kind of helper specialized template (traits) to deal with this.
Last edited on
Abramus... thanks again for your reply.

"count" is both an in and out parameter.

Pages: 12