Quick question on using template for two different functions

Hi, I have a question about template usage.

Say I have two functions, both named void func(). One of them takes in two of the same data type to perform one function, and the other takes in two different datatypes to perform a different function.

If I use
 
template <class A>

would void func(A, A) be the proper set up for taking in two of the same data type? So, if I had func(5, 8), it would work since both are integers; and if I had func(5, 8.5), it wouldn't because one is an integer and another is a double?

If I wanted to use func(5, 8.5), do I have to do something like:
 
template <class A, class B>
?


Now if that works, how would I define the function prototype in a header file?
Would I use
1
2
template <class A, class B>
void func(A, B);

as one function prototype for both?

Or would I have to declare them separately like:
1
2
3
4
5
template <class A, class B>
void func(A, B);

template <class A>
void func(A, A);
?
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <type_traits>

// http://en.cppreference.com/w/cpp/language/sfinae
// http://en.cppreference.com/w/cpp/types/enable_if
// http://en.cppreference.com/w/cpp/types/is_same
template < typename A, typename B >
typename std::enable_if< std::is_same<A,B>::value, void >::type
func( A, B ) { std::cout << "both parameters are of the same type\n" ; }

template < typename A, typename B >
typename std::enable_if< !std::is_same<A,B>::value, void >::type
func( A, B ) { std::cout << "parameters are of two diferent types\n" ; }

int main()
{
    func( 12, 16 ) ; // both parameters are of the same type
    
    func( 12, 16.0 ) ; // parameters are of two diferent types
}

http://coliru.stacked-crooked.com/a/758dab3355445745
Do you have different code to run if the two types the same? If you do, then overload:

1
2
3
4
5
6
7
8
template <class A, class B> void func(A, B); // #1
template <class A>          void func(A, A); // #2

int main()
{
    func(1, 2); // calls #2 with A = int
    func(1, 2.); // calls #1 with A = int, B = double
}

(EDIT: or enable_if as pointed out above)

if it's the same code whether the parameters have the same type or different types, then don't overload:

1
2
3
4
5
6
7
template <class A, class B> void func(A, B); // #1

int main()
{
    func(1, 2); // calls #1 with A = int, B = int
    func(1, 2.); // calls #1 with A = int, B = double
}
Last edited on
Thank you for clearing that up!

But now I don't really understand the errors I'm getting in my code since I used that form.

In a header file, I have:
1
2
3
4
5
template <class A>
void problem6_7(A, A);

template <class A, class B>
void problem6_7(A, B);


In a source file, I have:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class A>
void problem6_7(A a, A b){    // When two of the same type are passed in, the function swaps the values.

	A temp = a;
	a = b;
	b = temp;

}

template <class A, class B>
void problem6_7(A a, B b){     // When two of different types are passed in, the function sets both a and b to 0.

	a = 0;
	b = 0;

}



In the main, I have:
1
2
3
4
5
6
7
8
9
10
	std::string x = "test1";
	std::string y = "test2";
	problem6_7(x, y);
	int q = 6;
	float r = 2.0;
	problem6_7(q, r);
	if ( x != "test2" or y != "test1" or q != 0 or r != 0) {
		cout << "Failed\n";
	}



The error I'm getting is:
C:\Users\Kim\AppData\Local\Temp\ccUHIhpy.o:homework6_main.cpp:(.text+0x873): und
efined reference to `void problem6_7<std::string, std::string>(std::string, std:
:string)'
C:\Users\Kim\AppData\Local\Temp\ccUHIhpy.o:homework6_main.cpp:(.text+0x8bc): und
efined reference to `void problem6_7<int, float>(int, float)'
collect2.exe: error: ld returned 1 exit status
Template definitions go into headers, not into source files.
Hm, when I left them in only the header, I got this error instead:


C:\Users\Kim\Desktop\Homework 6>gcc homework6.cpp homework6_main.cpp -o test -ls
tdc++
homework6.cpp:111:17: error: variable or field 'problem6_7' declared void
homework6.cpp:111:17: error: 'A' was not declared in this scope
homework6.cpp:111:29: error: 'A' was not declared in this scope
homework6.cpp:120:17: error: variable or field 'problem6_7' declared void
homework6.cpp:120:17: error: 'A' was not declared in this scope
homework6.cpp:120:29: error: 'B' was not declared in this scope


Is there is some sort of method of including the template A and B in the source file without defining it?
The problem is that you have mis-formatted something somehow. If your template functions are declared exactly like you have above, then there shouldn't be any problem.

If there still is, then there is something nearby that is improperly declared that is messing with it.


(The compiler isn't recognizing 'problem6_7' as a function -- it thinks it is a variable, and you cannot create void variables.)

Any semicolons (;) where there shouldn't be?
When I commented out the part of the main that grades problem6_7,
1
2
3
4
5
6
7
8
9
10
	std::string x = "test1";
	std::string y = "test2";
	problem6_7(x, y);
	int q = 6;
	float r = 2.0;
	problem6_7(q, r);
	if ( x != "test2" or y != "test1" or q != 0 or r != 0) {
		std::cerr<<"problem6_7 failed, -10\n";
		score -= 10;
	}


it compiles successfully...

I'm not allowed to change the main, though, since it's my professor's.
Is there something about this part of the main code, related to my source and header, that is an issue?
Last edited on
None of the code you've shown so far is producing the compiler diagnostic you quoted, so it's very hard to guess what that code might look like.

If you put the 16 lines posted earlier under "In a source file, I have:" into a header file, and #include that header file in the source with the grading code quoted above (uncommented), it will compile and execute your templates (at which point it will execute score -= 10 because of an unrelated error having to do with pass-by-value and pass-by-reference semantics)
You're right. When I ran those selections by themselves, it worked perfectly and then deducted 10 points (I don't understand why that happens, yet, but I'm going to worry about that after I fix the current issue).


This is what the entire code looks like:

homework6.h:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/*******************************************************************************
 * Do not modify this file -- you should create a homework6.cpp file to
 * implement the functions described in this file.
 *
 * For the template problems, place your answers in homework6_templates.h
 ******************************************************************************/

#include <utility>
#include <vector>

//Return -1 if x < y, 0 if x == y, or +1 if x > y
int problem1(int x, int y);

//begin is a pointer to the beginning of an array and end is a pointer to
//just after the end of the array. This function returns a pointer to
//an element with the given value if it is in the range begin to end, or
//returns end if the value is not in the range.
int* problem2(int* begin, int* end, int value);

//Append b's values at the end of a and clear the values in b
void problem3(std::vector<int>& a, std::vector<int>& b);

//Searches for value in the given two dimensional matrix
//Returns the x,y coordinate of an element with that value
//or returns std::make_pair(-1, -1) if the element is not
//in the matrix
std::pair<int, int> problem4(std::vector< std::vector<int> >& matrix, int value);


//Return the number of steps taken if binary search were used to find
//value in values. Base your answer upon the code from lecture 8
int problem5(std::vector<int>& values, int value);

//Problems 6 and 7 are templates and go into homework6_templates.h

//If a is 0 then return b, if b is 0 then return a,
//otherwise return problem8(a/2, b/3) + problem8(a/3, b/2)
//Hint: this is a recursive function
int problem8(int a, int b);

//This class must remember how many instances of the class currently exist
class problem9 {
	public:
		//Total number of problem9s in existence
		static int total_problem9s;
		//Constructor sets number to the total number of problem9s in existence after this one is created
		problem9();
		~problem9();
};

class problem10 {
	private:
		problem9* data;	// Data points to a problem 9 object.
	public:
		//Constructor should initialize new memory for data
		problem10();
		//Destructor should give up memory used for data
		~problem10();

		//Get a reference to the value pointed to by data
		problem9& getValue();
};



homework6_main.cpp:
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "homework6.h"
#include "homework6_templates.h"

#include <iostream>
#include <string>
#include <vector>
#include <utility>

int main( int argc, char** argv) {
	int score = 100;

	if (-1 != problem1(-1, 10) or
			0 != problem1(20, 20) or
			1 != problem1(56, 12)) {
		std::cout<<"problem1 failed, -10\n";
		score -= 10;
	}

	int problem2_test[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	int* ans1 = problem2_test + 9;
	int* ans2 = problem2_test;
	int* ans3 = problem2_test+2;
	if (ans1 != problem2(problem2_test, problem2_test+9, 0) or
			ans2 != problem2(problem2_test, problem2_test, 2) or
			ans3 != problem2(problem2_test, problem2_test+9, 3)) {
		std::cout<<"problem2 failed, -10\n";
		score -= 10;
	}

	std::vector<int> a;
	a.push_back(1);
	a.push_back(2);
	a.push_back(3);
	std::vector<int> b;
	b.push_back(3);
	b.push_back(2);
	b.push_back(1);
	std::vector<int> result = a;
	result.push_back(3);
	result.push_back(2);
	result.push_back(1);
	problem3(a, b);
	if (a != result or not b.empty()) {
		std::cerr<<"problem3 failed, -10\n";
		score -= 10;
	}

	std::vector< std::vector<int> > matrix(3, std::vector<int>(3, 0));
	matrix.at(2).at(1) = 5;
	if (std::make_pair(2, 1) != problem4(matrix, 5) or
			std::make_pair(-1, -1) != problem4(matrix, 8)) {
		std::cerr<<"problem4 failed, -10\n";
		score -= 10;
	}


	std::vector<int> bin_vals;
	bin_vals.push_back(-1);
	bin_vals.push_back(1);
	bin_vals.push_back(2);
	bin_vals.push_back(3);
	bin_vals.push_back(4);
	if (1 != problem5(bin_vals, 2) or
			3 != problem5(bin_vals, 0) or
			2 != problem5(bin_vals, 4)) {
		std::cerr<<"problem5 failed, -10\n";
		score -= 10;
	}

	std::string x = "test1";
	std::string y = "test2";
	problem6_7(x, y);
	int q = 6;
	float r = 2.0;
	problem6_7(q, r);
	if ( x != "test2" or y != "test1" or q != 0 or r != 0) {
		std::cerr<<"problem6_7 failed, -10\n";
		score -= 10;
	}

	if (46 != problem8(100, 100)) {
		std::cout<<"Problem 8 failed, -10\n";
		score -= 10;
	}

	//Creation sets total to 1, then to 2, then deletion brings it to 1 again
	int zero = problem9::total_problem9s;
	problem9 p9;
	int one = problem9::total_problem9s;
	problem9* p9_p = new problem9();
	int two = problem9::total_problem9s;
	delete p9_p;
	int one_again = problem9::total_problem9s;
	if (0 != zero or
			1 != one or
			2 != two or
		  1 != one_again) {
		std::cerr<<"problem9 failed, -15\n";
		score -= 15;
	}

	int two_again, now_three;
	{
		problem10 p10_1;
		two_again = problem9::total_problem9s;
		problem10 p10_2;
		now_three = problem9::total_problem9s;
	}
	int back_to_one = problem9::total_problem9s;
	if (2 != two_again or
			3 != now_three or
			1 != back_to_one) {
		std::cerr<<"problem10 failed, -15\n";
		score -= 15;
	}

	//Print out the final score after all tests
	std::cerr<<"Score is "<<score<<" out of "<<100<<'\n';
	std::cerr<<"This assignment is worth 15 points, including 5 extra points to help make up for any bad days you've had this semester.\n";
}


homework6_templates.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Write a template function named "problem6_7" to swap two arguments of the *same* type
//The return type is void and the two arguments are taken in by reference

//Write a template function named "problem6_7" that accepts two arguments of *different* types
//and sets them both equal to 0. 
//This function's prototype must match the previous function's exactly; c++ will decide
//which to call based upon their specificity

#ifndef HOMEWORK6_TEMPLATES_H
#define HOMEWORK6_TEMPLATES_H

template <class A>
void problem6_7(A, A);

template <class A, class B>
void problem6_7(A, B);


#endif 



Last edited on
(Post was too long...)

homework6.cpp:
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include "homework6.h"
#include "homework6_templates.h"
#include <iostream>
#include <utility>	// Includes std::pair
#include <vector>
#include <string>

using namespace std;


/* Problem 1 */

int problem1(int x, int y){

	if(x < y){
		return (-1);
	} else if(x == y){
		return 0;
	} else if(x > y){
		return 1;
	}

}


/* Problem 2 */

int* problem2(int* begin, int* end, int value){

	for(int* i = begin; i < end; i++){

		if(value == *i){
			return i;
		}

	}

	return end;

}


/* Problem 3 */

void problem3(vector<int>& a, vector<int>& b){

	for(int i = 0; i < b.size(); i++){

		a.push_back(b[i]);

	}

	b.clear();

}


/* Problem 4 */

pair<int, int> problem4(vector< vector<int> >& matrix, int value){

	for(int row = 0; row < matrix[0].size(); row++){
		for(int column = 0; column < matrix.size(); column++){

			if(matrix[row][column] == value){
				pair<int, int> coordinate(row, column);
				return coordinate;
			}

		}
	}

	return make_pair(-1, -1);

}


/* Problem 5 */

int problem5(vector<int>& values, int value){

	int begin = 0;
	int end = values.size();
	int counter = 0;

	while(begin != end){

		int middle = (begin + end)/2;

		if(values.at(middle) == value){
			counter++;
			return counter;

		} else if(values.at(middle) < value){
			counter++;
			begin = middle + 1;

		} else {
			counter++;
			end = middle;

		}

	}

	return counter;

}



/* Problem 6 & 7: */

void problem6_7(A a, A b){    // When two of the same type are passed in, the function swaps the values.

	A temp = a;
	a = b;
	b = temp;

}

void problem6_7(A a, B b){     // When two of different types are passed in, the function sets both a and b to 0.

	a = 0;
	b = 0;

}



/* Problem 8 */

int problem8(int a, int b){

	if(a == 0){
		return b;
	} else if(b == 0){
		return a;
	} else {
		return problem8(a/2, b/3) + problem8(a/3, b/2);
	}

}


/* Problem 9 */

int problem9::total_problem9s = 0;

problem9::problem9(){
	total_problem9s++;	// Increments the total number of problem 9 objects since the constructor is called every time an object is created
}

problem9::~problem9(){
	total_problem9s--;	// Decrements the total number of problem 9 objects since the deconstructor is called every time an object is deleted from memory
}




/* Problem 10 */

problem10::problem10(){

	data = new problem9;	// The data pointer points to a new problem9 object's newly allocated memory location
}

problem10::~problem10(){
	delete data;	// data is deleted, so the memory address of a problem9 object is now unassigned/empty.
}

problem9& problem10::getValue(){	// This function returns an address
	return *data;	// data points to addresses
}



This is the error I get when I run exactly what I've posted:


homework6.cpp:113:17: error: variable or field 'problem6_7' declared void
homework6.cpp:113:17: error: 'A' was not declared in this scope
homework6.cpp:113:22: error: 'A' was not declared in this scope
homework6.cpp:121:17: error: variable or field 'problem6_7' declared void
homework6.cpp:121:17: error: 'A' was not declared in this scope
homework6.cpp:121:22: error: 'B' was not declared in this scope



I feel like I've defined problem6_7 as a function, unless I'm being crazy, so I'm really stumped as to why I'm getting that error.

And when the main code relating to problem6_7 is commented out, everything works as it should and I get the score of 100.
Last edited on
closed account (j3Rz8vqX)
An example of a working template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//header.h
template <class A>
void myFunction(A a, A b)
{
    cout<<"===Before==="<<endl;
    cout<<"a = "<<a<<"\nb = "<<b<<endl;
    a=b;
    cout<<"===After==="<<endl;
    cout<<"a = "<<a<<"\nb = "<<b<<endl;
}
template <class A,class B>
void myFunction(A a, B b)
{
    cout<<"===Before==="<<endl;
    cout<<"a = "<<a<<"\nb = "<<b<<endl;
    a=b;
    cout<<"===After==="<<endl;
    cout<<"a = "<<a<<"\nb = "<<b<<endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//main.cpp
#include <iostream>
#include <string>
using namespace std;

#include "header.h"

int main()
{
    int i=1,j=2;
    float f=3,d=4;
    myFunction(i,j);
    myFunction(f,d);
    myFunction(i,d);
	return 0;
}


I feel |absolutely| crazy. I used a format identical to Dput's code, but for some reason my function is being read as a variable, and A and B are not in the scope, even when my header is included in my source code.
closed account (j3Rz8vqX)
Move your definitions into the header.

Template declaration and prototype must be within the same file.
Oh... I feel incredibly silly.
Thank you! That fixed everything.
Topic archived. No new replies allowed.