Template Class Linked List Insertion Error - c++

When I attempt to insert this 'food' object into my template class linked list 'test'. I get this error:
request for member ‘addNode’ in ‘test’, which is of non-class type ‘Catalog<FoodSource>()
Here's my coding, What am I doing wrong?
##main:##
int main(void)
{
Catalog<FoodSource> test();
FoodSource food();
test.addNode(const &food);
return(0);
}
##function definition in .h:##
template<class T>
class Catalog
{
public:
void addNode(const T& value);
};
##function implementation in .cpp:##
template <class T>
void Catalog<T>::addNode(const T& value)
{
Node *temp;
if(head == NULL)
head = new Node (value, NULL);
else
{
temp=head;
while(temp->next !=NULL)
temp=temp->next;
temp->next = new Node (value, NULL);
}
}

You just found one of the many warts present in the C++ syntax. The standard requires that if an expression can be interpreted both as a declaration and as a definition then it must be considered as a declaration. For example your code
Catalog<FoodSource> test();
is not defining a variable named test but is instead declaring that there is a function named test that takes no arguments and that returns a Catalog<FoodSource> instance.
To define the variable you need to omit the parenthesis.
Note that there are cases where this trap is much harder to notice... for example:
double x = 3.14159;
int y(int(x));
as surprising it may seem in the above code y is declared as a function!

Declaration and implementation of a class template should be in the same file.
Also, you can just call test.addNode(food); in main.

Given definition for all the classes Node, FoodSource etc is available, you need to do at least the following:
1) Move the function definition to .h file
2) The first line in main function is ambigous. It should be rewritten as Catalog<FoodSource> test; because Catalog<FoodSource> test() will be treated as function prototype

Related

C++: How to implement private helper function that requires access to protected members of a class without altering header file?

I'm trying to declare and use a generic helper function to do recursion.
The issue is, I cannot touch the default header file.
We are allowed to linked the default header file and add implementation to another header file, however, I don't know how to add more functions to the class Node declared in the default without the redefinition error.
Note: there are getters for the Node class but no setters, same for Tree.
Note2: We can only linked the default header file, cannot add other headers files.
What I want if I can declare the helper:
template <class T>
void Tree<T>::add(const T &x){
if(root){
root->insertNode(x);
} else{
root = new Node<T>(x);
}
}
template <class T>
void Node::insertNode(T const &x){
if(x < value){
if(left){
left->insertNode(x);
} else{
left = new Node<T>(x);
}
} else if(x > value){
if(right){
right->insertNode(x);
} else{
right = new Node<T>(x);
}
}
}
Which leads to this error:
Out-of-line definition of 'insertNode' does not match any declaration in 'Node<T>'
Because the helper function wasn't defined in the default header.
I can't declare Node::insertNode without changing the default header.
As you can see, the helper needs access to protected members of Node (data, left, right).
I tried passing (Node*) as additional parameter to the helper as a free function, but then I don't know how to set left and right with just getters (there are no setter functions in the header).
So I can't set it to a free function without declaring it as friend in the header, which again, I can't touch.
What can I do? Suggestion?
Edit:
Following suggestion of #darune, I tried passing in reference as param:
template <class Base>
void insertNode(const Base &item, Node<T>& node){
if(item < node->data){
if(node->left){
insertNode(item, node->left);
} else{
node->left = new BSTNode<Base>(item);
}
} else if(node->data > item){
if(node->right){
insertNode(item, node->right);
} else{
node->right = new BSTNode<Base>(item);
}
}
}
But then I get:
error: base operand of '->' has non-pointer type 'Node<int>'
if(item < node->data)
If I try to change the -> to . (like node.data), then it just says:
Node<T>::data is protected within this context
Edit2:
Using template argument as reference param (not sure if correct):
template <class T, class S>
void insertNode(const Base &item, S& node){
if(item < node->data){
if(node->left){
insertNode(item, node->left);
} else{
node->left = new BSTNode<Base>(item);
}
} else if(node->data > item){
if(node->right){
insertNode(item, node->right);
} else{
node->right = new BSTNode<Base>(item);
}
}
}
Gives me the same issue as above:
error: base operand of '->' has non-pointer type 'Node<int>'
if(item < node->data)
According to the language rules you cannot add a member helper function without modifying the header file.
What you could do:
Either create standalone helper function (non-member) and work with the public interface of Node
or
Create a wrapper, for ex. class NodeWrapper : public Node and work with the wrapper class:
template <typename T>
class NodeWrapper : public Node<T>
{
void insertNode(const T& x)
{
... rest of the code ...
... you can access protected member of Node here, but not the private ones
}
}
You could just pass a reference (or a pointer) to the protected/private member into the function that needs to work on it. That way you still uphold all language and design principles. Also an added benefit is improved encapsulation.
Something like:
void insertNode(const auto& x, auto& left, auto& right){
Also, try to avoid using raw pointers in c++ (unless you have a good reason to). It's the modern way. Passing a raw pointer to a function is the only place where it still makes sense, since means it is optional (and hence should be reflected inside the function).

Compiler error in default parameters in class

I'm trying to pass the second argument optional to my search function:
class ExponentialTree
{
public:
node* Search(int num, node* curr_node=root);
void Insert(int num);
private:
node* root;
};
node* ExponentialTree::Search(int num, node* curr_node)
{
If I call with one parameter, I want it to set it to root. I tried defult parameter in declaration, default parameter in implementation, both(I know its not true), two declaration. Nothing worked. Any ideas? I don't want overloading method beacuse it is the only line that will change.
Thanks.
Use:
node* Search(int num, node* curr_node=NULL);
and handle the case of NULL pointer in the body of the function:
node* Search(int num, node* curr_node)
{
if (curr_node == NULL){
//...
}
//...
}
Or it can be set in the implementation part too, but just with NULL.
A non-static member variable can not be used as a default argument.
Below is the relevant section in C++ standard draft (N3225), section § 8.3.6, point 9:
.. a non-static member shall not be used in a default argument expression, even if it
is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless
it is used to form a pointer to member (5.3.1). [ Example: the declaration of X::mem1() in the following
example is ill-formed because no object is supplied for the non-static member X::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a); // error: non-static member a
// used as default argument
int mem2(int i = b); // OK; use X::b
static int b;
};
root is a non-static member variable here -- hence you can not specify it as a default argument.
This is a classic example of where you actually would gain from using an overload:
node* Search(int num, node* curr_node)
{
// Your implementation
}
and then
inline node* Search(int num) { return Search(num, root); }
Hereby you explicitly state, that when no parameter is given, you should use root as the value for curr_node.
There is no need to make a runtime test, when the code can be decided at compile time, and you don't have to write NULL when you actually mean root.

Can I use a member element as the default argument for a method of the class?

The method Minimum returns the minimum element in the binary search tree. If no argument is passed it prints the minimum of calling object. If address of a node is passed it prints the minimum of the subtree whose root is node
When compiled it shows "Invalid use of non static data member Tree::root"
#include<stdlib.h>
#include<iostream>
class Node
{
public:
Node *leftchild;
Node *rightchild;
Node *parent;
int info;
};
class Tree
{
public:
Node *root;
Tree()
{
root=NULL;
}
void Minimum(Node*);
};
void Tree::Minimum(Node *curnode=root)
{
Node *parent;
while(curnode!=NULL)
{
parent=curnode;
curnode=curnode->leftchild;
}
std::cout<<parent->info<<endl;
}
int main()
{
Tree tree;
tree.Minimum();
return 0;
}
No, you cannot.
For the default value you can use either a value, a variable or a function that is accessible in the context of the function definition that is, in the class definition, which is outside of any particular object's context.
It usually helps me thinking on how the compiler really processes this. In particular, when the compiler does overload resolution for a function and finds an overload that has more arguments than those used at the place of call, the compiler will generate code at the place of call to fill in the rest of the arguments. The generated code will always generate a call with all of the arguments:
int g();
void f(int x = g());
int main() {
f(); // [1]
}
When the compiler processes [1] and it does overload resolution it finds that void ::f(int x = g()) is the best candidate and picks it up. It then fills the default argument and generates the call for you:
int main() {
f( /*compiler injected*/g() );
}
If you consider a call to a member function, or a member variable of the class, it would not make sense in the context of the caller (the language could be changed to adapt to this, it is not impossible to handle that, but with the current model it does not work).
You can alternatively set it to NULL for example as default, and then check and set it to the member in the method.
Or overload the method with void Minimum(); and in that method call the one with an argument with the member.
void Tree::Minimum() {
Minimum(root);
}
I couldn't find any way to get the default parameter to work like that. But you can get the same result by overloading the function, like so:
class Tree
{
public:
Node *root;
Tree()
{
root=NULL;
}
void Minimum(Node*);
void Minimum();
};
void Tree::Minimum(Node *curnode)
{
Node *parent;
while(curnode!=NULL)
{
parent=curnode;
curnode=curnode->leftchild;
}
std::cout<<parent->info<<std::endl;
}
void Tree::Minimum()
{
Minimum(root);
}
If the case where an argument of NULL is explicitly passed doesn't need to be differentiated from no argument being passed, you could set NULL as the default and use root if curnode is NULL.
void Tree::Minimum(Node *curnode=NULL)
{
if (curnode==NULL)
curnode = root;
Node *parent;
while(curnode!=NULL)
{
parent=curnode;
curnode=curnode->leftchild;
}
std::cout<<parent->info<<endl;
}

Template Type is undefined

I'm learning C++ and now I'm working with Template.
I'm trying to implement a Linked List:
ListElement.hpp
#ifndef LIST_ELEMENT_HPP_
#define LIST_ELEMENT_HPP_
template <class Type> class SingleLinkedList;
template <class Type>
class ListElement
{
public:
ListElement(const Type element);
~ListElement(void);
public:
Type val;
ListElement* next;
};
#endif
ListElement.cpp:
#include "ListElement.hpp"
ListElement<Type>::ListElement(const Type element)
{
*next = NULL;
val = element;
}
ListElement<Type>::~ListElement(void)
{
}
I'm getting an Error on ListElement.cpp releated to Type: Type is undefined.
I have found a lot of examples about how to implement a Linked List but none using a separated hpp and cpp.
Do you know how can I fix this error?
First problem:
You need to fix the way you are defining the member functions of your class template:
template<typename Type> // <== ADD THIS!
ListElement<Type>::ListElement(const Type& element)
// ^
// And perhaps also this?
// (don't forget to modify the
// corresponding declaration if
// you change it)
{
*next = NULL;
val = element;
}
Second problem:
You should move those definitions to the same header file that contains the definition of the class template, or the linker will complain about undefined references. For more information, see this Q&A on StackOverflow.
Third problem:
In your constructor, you are currently causing undefined behavior by dereferencing an uninitialized pointer. You shouldn't be doing:
*next = NULL;
^^^^^^^^^^^^^
Undefined Behavior! next is uninitialized and you are dereferencing it!
But rather:
next = NULL;
Or even better (using constructor initialization lists and C++11's nullptr):
template<typename Type>
ListElement<Type>::ListElement(const Type& element) :
val(element),
next(nullptr)
{
}
Firstly - in general you cannot split declaration and implementation of template class in different files.
Secondly - before implementation should be template decl.
template<typename Type>
ListElement<Type>::ListElement(const Type element)
{
next = NULL;
val = element;
}
At first try to add
template<class Type>
before each function in .cpp file
It wouldn't work. (Linker errors) So move all your implementation to .h file.
Then perhaps you should change
ListElement(const Type element);
to
ListElement(const Type &element);

C++ Invalid use of member function, did you forget the ( )?

I'm working on an assignment where I create my own container using templates. The container I am required to use is called Smaph, which takes in two pairs of numbers and does a variety of functions with them. I am only allowed to make a header file for this assignment. I've created a singly-linked class slink, that takes one template argument.
Currently, I am trying to get a feel for templates and learning how to use them, so I have a very simple example I was hoping you could help me with. I have a push_back function in my singly linked list class to add to my templates. For some reason, I can't add things to my slink because I get a compile time error that says, Invalid use of member function, (push_back), did you forget the ( )? Can someone explain to me why I am getting this error?
Thank you!
template <typename T>
class slink {
private:
struct node {
T datum;
struct node *next;
};
node *head, *tail;
public:
slink() : head(0), tail(0) {
}
~slink() {
clear();
}
void push_back(const T &datum) {
node *p = new node;
p->datum = datum;
p->next = 0;
if (!tail)
head = p;
else
tail->next = p;
tail = p;
}
template <typename Tfirst, typename Tsecond>
class Smaph {
public:
Smaph();
~Smaph();
Smaph(const Tfirst a, const Tsecond b) {
std::pair<Tfirst, Tsecond> pair1(a, b);
s.push_back(pair1);
}
private:
slink<std::pair<Tfirst, Tsecond> > s();
};
And finally, my main to test my program. All I want to do right now is add these two numbers to my singly linked list through my Smaph.
int main() {
Smaph<int, double> s(3, 6.3);
}
slink<std::pair<Tfirst, Tsecond> > s();
This is a declaration of a function called s that takes no arguments and returns a slink<std::pair<Tfirst, Tsecond> >. When the compiler sees you do s.push_back(pair1);, it wonders what you're trying to do to that poor function. Remove the () to make it a data member:
slink<std::pair<Tfirst, Tsecond> > s;
On this line you did:
slink<std::pair<Tfirst, Tsecond> > s();
This is declaring a function named s that returns slink<std::pair<Tfirst, Tsecond> >. But then you did this inside one of your member functions:
s.push_back(pair1);
That isn't right, which is why your compiler alerts you of invalid use of this member function.
To fix, remove the parameters:
slink<std::pair<Tfirst, Tsecond> > s;