Function Call is Undefined

Sep 5, 2019 at 12:28am
I have a function that works fine when I created it in main. I moved it to a implementation file, and placed the the prototype in a template class. Now I am getting an error under the function call:

Severity Code Description Project File Line Suppression State
Error (active) E0020 identifier "noDuplicates" is undefined Project29

I think I may have something wrong with the syntax in the definition and prototype but I'm not sure. I am learning templates and how the files work with them so this is all new and I am trying to understand it.

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
 template<class ItemType>
class ArraySet : public SetInterface<ItemType>
{
private:
	const int END = 6;
	static const int DEFAULT_CAPACITY = 6; // Small size to test for a full bag
	ItemType items[DEFAULT_CAPACITY];      // Array of bag items
	int itemCount;                         // Current count of bag items 
	int maxItems;                          // Max capacity of the bag

	

public:
	ArraySet();
        ArraySet& noDuplicates(const ArraySet<ItemType>& set, std::string items[]);
	
}; 
#include "ArraySet.cpp" // Pound include here so I can remove ArraySet.cpp from compiler. 



// ArraySet.cpp is in different file with the same project. Removed from the Solution Explorer though in Visual Studio.
template<class ItemType>
ArraySet<ItemType>& ArraySet<ItemType>::noDuplicates(const ArraySet<ItemType>& set, std::string items[])
{
	for (int index = 0; index < END; index++)
	{
		std::string& firstItem = items[index];
		for (int nextIndex = index + 1; nextIndex < END; nextIndex++) {

			if (firstItem == items[nextIndex])
				set.remove(items[nextIndex]);
		}
	}
}





// Function in client program.
void setTester(ArraySet<string>& set)
{
	cout << "isEmpty: returns " << set.isEmpty()
		<< "; should be 1 (true)" << endl;
	displaySet(set);

	std::string items[] = { "one", "two", "three", "four", "five", "one" };
	cout << "Add 6 items to the set: " << endl;
	for (int i = 0; i < END; i++)
	{
		set.add(items[i]);
	}  // end for
	
	displaySet(set);
	noDuplicates(set, items); // ERROR here .....................................................
	cout << "After removing any duplicate values." << endl;
	displaySet(set);
}







// main
int main()
{
	
	ArraySet<std::string> set;
	cout << "Testing the Array-Based set:" << endl;
	cout << "The initial set is empty." << endl;
	setTester(set);
	


Last edited on Sep 5, 2019 at 12:30am
Sep 5, 2019 at 12:32am
You are calling noduplicates as a free function, when it is a class function.
Last edited on Sep 5, 2019 at 12:43am
Sep 5, 2019 at 12:58am
Oh okay. So I would need to create an object of the class and then call it with the object. Is that correct? This is what I just tried but didn't get it right.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void setTester(ArraySet<string>& set)
{
	ArraySet callFunction;
	

	cout << "isEmpty: returns " << set.isEmpty()
		<< "; should be 1 (true)" << endl;
	displaySet(set);

	std::string items[] = { "one", "two", "three", "four", "five", "one" };
	cout << "Add 6 items to the set: " << endl;
	for (int i = 0; i < END; i++)
	{
		set.add(items[i]);
	}  // end for
	
	displaySet(set);
	callFunction.noDuplicates(set, items);
}

Error:
Severity Code Description Project File Line Suppression State
Error (active) E0441 argument list for class template "ArraySet" is missing Project29
Last edited on Sep 5, 2019 at 12:59am
Sep 5, 2019 at 1:05am
I tried changing it to match the template but that leads to a different error.

1
2
3
4
template<class ItemType>
void setTester(ArraySet<ItemType>& set)
{
}

Severity Code Description Project File Line Suppression State
Error (active) E1776 function "ArraySet<ItemType>::operator=(const ArraySet<std::string> &) [with ItemType=std::string]" (declared implicitly) cannot be referenced -- it is a deleted function
Sep 5, 2019 at 1:24am
Can you show the code that you have changed?
Sep 5, 2019 at 1:37am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<class ItemType>  // Changed
void setTester(ArraySet<ItemType>& set) // Changed
{
	ArraySet callFunction;         // Added an object
	

	cout << "isEmpty: returns " << set.isEmpty()
		<< "; should be 1 (true)" << endl;
	displaySet(set);

	std::string items[] = { "one", "two", "three", "four", "five", "one" };
	cout << "Add 6 items to the set: " << endl;
	for (int i = 0; i < END; i++)
	{
		set.add(items[i]);
	}  // end for
	
	displaySet(set);
	callFunction.noDuplicates(set, items);  // Calling function with object.
	cout << "After removing any duplicate values." << endl;
	displaySet(set);
}
Sep 5, 2019 at 3:24am
Yea post all your code, I am lost.
Sep 5, 2019 at 4:55am
stoneJax wrote:

So I would need to create an object of the class and then call it with the
object.


Why would you need to create another object when you already have one?

1
2
3
4
5
6
void setTester(ArraySet<string>& set) {
  /* Your parameter 'set' is already an object, isn't it? So why not just call
   * it with that same object? */

   set.noDuplicates(set, items); // like this
}


In your noDuplicates function, you have the first parameter is an object of the
class. You should not have to do that, since functions of the class already
have access to the object via the keyword this.

Instead you can implement it like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
template<class ItemType>
ArraySet<ItemType>& ArraySet<ItemType>::noDuplicates(std::string items[])
{
  for (int index = 0; index < END; index++)
  {
    std::string& firstItem = items[index];
    for (int nextIndex = index + 1; nextIndex < END; nextIndex++) {

      if (firstItem == items[nextIndex])
        this->remove(items[nextIndex]);
    }
  }
}


You can either do that, or make the noDuplicates function in the class
static. This elimates the need to create an object just to access
the function.

1
2
3
4
5
class ArraySet: public SetInterface<ItemType> {
   /* ... */
   public:
     static ArraySet& noDuplicates(const ArraySet<ItemType>& set, std::string items[]);
};




EDIT:

stoneJax wrote:

Error:
Severity Code Description Project File Line Suppression State
Error (active) E0441 argument list for class template "ArraySet" is missing Project29


You're getting this because this line:

1
2
3
4
5
6
7
ArraySet callFunction;

/* You're not giving a data type to the object. Remember you implement the
 * class with a template, so you have to do
 * 
 *   ArraySet<TYPE> someObject;
 * */

Last edited on Sep 5, 2019 at 5:01am
Sep 5, 2019 at 5:37am
Thank you, you hit on a lot of good points that makes sense. I got rid of the the extraneous object and object parameter. I called noDuplicates with the set object, and used the this pointer like you mentioned. However, I get this error:

Severity Code Description Project File Line Suppression State
Error C4716 'ArraySet<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::noDuplicates': must return a value

I tried returning the function with "return this;" and "return items;" but that didn't work.
Sep 5, 2019 at 5:47am
Here is my updated code:

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
// Client file
template<class ItemType>
void setTester(ArraySet<ItemType>& set)  
{
	cout << "isEmpty: returns " << set.isEmpty()
		<< "; should be 1 (true)" << endl;
	displaySet(set);
	
	std::string items[] = { "one", "two", "three", "four", "five", "one" };
	cout << "Add 6 items to the set: " << endl;
	for (int i = 0; i < END; i++)
	{
		set.add(items[i]);
	}  // end for

	displaySet(set);
	set.noDuplicates(items);  // Corrected by calling with set object.


	cout << "After removing any duplicate values." << endl;
	displaySet(set);
}




// Implementation file
template<class ItemType>
ArraySet<ItemType>& ArraySet<ItemType>::noDuplicates(std::string items[]) // Got rid of extra object parameter.
{
	for (int index = 0; index < END; index++)
	{
		std::string& firstItem = items[index];
		for (int nextIndex = index + 1; nextIndex < END; nextIndex++) {

			if (firstItem == items[nextIndex])
				this->remove(items[nextIndex]);
		}
	}
}

Severity Code Description Project File Line Suppression State
Error C4716 'ArraySet<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::noDuplicates': must return a value


I should note that making these changes affected some things in main that were working fine before. Things meaning calls to other functions which are assigned to objects. I get an error at the assignment operator. I figure that we focus on one thing (above) at a time though, so I don't want to overload with secondary errors.
Last edited on Sep 5, 2019 at 6:03am
Sep 5, 2019 at 5:53am
You do not need to return a value. Make it void unless you really do want to use the returned data for something. In this case, I don't really see that you need to.
Sep 5, 2019 at 6:25am
Oh okay. Awesome, thank you, that simplifies things and noDuplicates seems to be working now.

Unfortunately, these changes created some problems in main. I can't make sense of it though because these changes seem to be independent from any of the other functions. I'll post my main below with the error. The errors show up where all the = signs are.

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

int main()
{
	bool returnFromUnion;
	const int LIMIT = 3;
	ArraySet<std::string> set1;
	ArraySet<std::string> set2;
	ArraySet<std::string> set3;
	ArraySet<std::string> intersection;
	ArraySet<std::string> difference;
	
	ArraySet<std::string> set;
	cout << "Testing the Array-Based set:" << endl;
	cout << "The initial set is empty." << endl;
	setTester(set);
	
	std::string items1[] = { "one", "two", "three" };
	cout << "Add 3 items to the set1: " << endl;
	for (int i = 0; i < LIMIT; i++)
	{
		set1.add(items1[i]);
	}  // end for
	
	std::string items2[] = { "four", "five", "six" };
	cout << "Add 3 items to the set2: " << endl;
	for (int i = 0; i < LIMIT; i++)
	{
		set2.add(items2[i]);
	}  // end for
	cout << "\nset1: " << endl;
	displaySet(set1);
	cout << "set2: " << endl;
	displaySet(set2);

	
	set3 = set1.setUnion(set2, returnFromUnion);
	if (returnFromUnion)
	{
		cout << "The union is: " << endl;
		displaySet(set3);
	}
	else cout << "The Union overflowed." << endl;
	

	intersection = set1.setIntersection(set2);
	cout << "The intersection is: " << endl;
	displaySet(intersection);

	set2.clear();
	cout << "Changing set2 to further test setIntersection." << endl;
	std::string changeItems2[] = { "one", "five", "three" };
	cout << "Add 3 items to the set2: " << endl;
	for (int i = 0; i < LIMIT; i++)
	{
		set2.add(changeItems2[i]);
	}  
	cout << "\nset2: " << endl;
	displaySet(set2);

	intersection = set1.setIntersection(set2);
	cout << "The intersection is: " << endl;
	displaySet(intersection);

	difference = set1.setDifference(set2);
	cout << "The difference is: " << endl;
	displaySet(difference);

	cout << "All done!" << endl;
	
	return 0;
} // end main 


Severity Code Description Project File Line Suppression State
Error (active) E1776 function "ArraySet<ItemType>::operator=(const ArraySet<std::string> &) [with ItemType=std::string]" (declared implicitly) cannot be referenced -- it is a deleted function
Sep 5, 2019 at 6:47am
If it helps I'll post the full 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
template<class ItemType>
class ArraySet : public SetInterface<ItemType>
{
private:
	const int END = 6;
	static const int DEFAULT_CAPACITY = 6; // Small size to test for a full bag
	ItemType items[DEFAULT_CAPACITY];      // Array of bag items
	int itemCount;                         // Current count of bag items 
	int maxItems;                          // Max capacity of the bag

	// Returns either the index of the element in the array items that
	// contains the given target or -1, if the array does not contain 
	// the target.
	int getIndexOf(const ItemType& target) const;

public:
	ArraySet();
    void noDuplicates(std::string items[]);
	ArraySet& setUnion(const ArraySet& set2, bool& failure);
	ArraySet& setIntersection(const ArraySet& set2);
	ArraySet& setDifference(const ArraySet& set2);
	int getCurrentSize() const;
	bool isEmpty() const;
	bool add(const ItemType& newEntry);
	bool remove(const ItemType& anEntry);
	void clear();
	bool contains(const ItemType& anEntry) const;
	std::vector<ItemType> toVector() const;
}; // end ArrayBag 
Sep 5, 2019 at 7:21am
1
2
3
ArraySet& setUnion(const ArraySet& set2, bool& failure);
ArraySet& setIntersection(const ArraySet& set2);
ArraySet& setDifference(const ArraySet& set2);


These three returns an address to an ArraySet object.

1
2
3
4
5
ArraySet<std::string> set1;
ArraySet<std::string> set2;
ArraySet<std::string> set3;
ArraySet<std::string> intersection;
ArraySet<std::string> difference;


You have these objects of the class, but none of them are pointers. Can you see the problem when you try to assign a non pointer to a reference?

EDIT: Ignore that. It seems I have forgotten references.
Last edited on Sep 5, 2019 at 8:19pm
Sep 5, 2019 at 7:23am
In several place like line 36, 45, etc. you try to copy the result of that functions (setUnion(...), setIntersection(...), etc.) to ArraySet. This is not allowed due to the constant member END.

By the way: setUnion(...), setIntersection(...), setDifference(...) return a non const reference ArraySet&. This is impossible without a global/static variable which is most likely not correct.
Sep 5, 2019 at 7:57am
@ fiji885 are you saying if I change

1
2
3
4
5
ArraySet<std::string> set1;
ArraySet<std::string> set2;
ArraySet<std::string> set3;
ArraySet<std::string> intersection;
ArraySet<std::string> difference;


so they are pointer objects then the function calls will work correctly? I'm confused because these objects and functions were working fine before I changed noDuplicates.

@ coder777, not sure what you mean here: "By the way: setUnion(...), setIntersection(...), setDifference(...) return a non const reference ArraySet&. This is impossible without a global/static variable which is most likely not correct."

I commented out the constant member END, and hard coded a 6 in the for loop for the noDuplicates function and everything seems to work. However, I have been told (in school) that hard coding values is not good programming practice, and I'm not supposed to do that.

Actually I just added static to the constant member END and that seems to have done the trick. Code is compiling with expected results. Do you guys feel that I am going about it the best way?
Sep 5, 2019 at 8:20am
I commented out the constant member END
Instead of static you can use enum:
enum { END = 6, DEFAULT_CAPACITY = 6 };

Do you guys feel that I am going about it the best way?
How ist it possible that those functions return ArraySet& (as a reference)?
If you modify the object itself why whould you want to copy it to another set?
Sep 5, 2019 at 7:12pm
> How ist it possible that those functions return ArraySet& (as a reference)?
return *this;

> If you modify the object itself why whould you want to copy it to another set?
method chaining
and you copy because you want a copy
¿do you consider this error-prone or non-intuitive?


@OP:
1
2
3
	intersection = set1.setIntersection(set2);
	//here `set1' has the intersection of both sets, ¿is that what you want?
	difference = set1.setDifference(set2);
Sep 6, 2019 at 4:23am
I appreciate everyone's input. Definitely helps, thank you.
Topic archived. No new replies allowed.